10

这是我的场景:

  • Web 应用程序为许多应用程序执行某种 SSO
  • 登录用户而不是单击链接,应用程序会向适当的应用程序发布用户信息(名称、密码 [无用]、角色)
  • 我正在其中一个应用程序上实现 SpringSecurity 以从其功能中受益(会话中的权限、其类提供的方法等)

所以,我需要开发一个自定义过滤器- 我猜 - 能够从请求中检索用户信息,从数据库中检索,通过自定义DetailsUserService,有关用户的更多信息(电子邮件等......),然后执行身份验证根据从请求中检索到的角色,该用户。

我正在查看预身份验证过滤器,但我不确定它是否是正确的选择。当主体已经在会话中时,似乎应该使用这些对象,这是由一些先前的身份验证机制提出的(对吗?)。

我认为,一旦确定了正确的过滤器,我应该需要执行以下操作:

GrantedAuthority[] ga= new GrantedAuthority[1];
ga[0] = new GrantedAuthorityImpl(myUser.getRole());

SecurityContext sc = SecurityContextHolder.getContext();
Authentication a = new UsernamePasswordAuthenticationToken(userName, userPwd, ga);
a = authenticationManager.authenticate(a);
sc.setAuthentication(a);

这是解决我的问题的正确方向吗?你有什么建议可以帮助我找到缺少的东西吗?

谢谢你们,

卢卡

添加:

嗨,Xearxess!很抱歉再次打扰您,但根据 SpringSecurity 2.0.4 翻译您的代码似乎比我想象的要困难:S 问题是 XML ......我尝试了不同的配置,但我总是遇到命名空间问题,缺少属性, ETC...

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:security="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">  

    <security:http>
        <security:intercept-url pattern="/**" access="isAuthenticated()" />
        <security:logout logout-url="/logout" logout-success-url="http://milan-ias-vs.usersad.everis.int/DMTest/" invalidate-session="true" />
        <security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthenticatedProcessingFilter" />
    </security:http>

    <bean id="preAuthenticatedProcessingFilter" class="it.novartis.ram.authentication.PreAuthenticatedProcessingFilter">
        <custom-filter position="PRE_AUTH_FILTER"/>
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean class="it.novartis.ram.authentication.PreAuthenticatedUserDetailsService" />
        </property>
    </bean>

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="preauthAuthProvider" />
    </security:authentication-manager>

</beans>

引用 CUSTOM-FILTER 元素的 2 行是两个不同的尝试,它们都被标记为错误。如何将过滤器的位置指定为属性?

身份验证管理器定义上的身份验证提供程序引用也被标记为错误。我认为我也需要像属性一样指定它,对吗?

希望你能给我最后一击;)再次感谢你,

卢卡

4

2 回答 2

31

为了完整起见,在 Spring Security 4 中进行了轻微更改。例如,强烈建议使用 Java 配置。这样就更容易与 Spring Boot 集成。

它遵循与上述答案中给出的 XML 配置等效的 Java 配置。

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(customAuthFilter(), AbstractPreAuthenticatedProcessingFilter.class)
            .authenticationProvider(preauthAuthProvider())
            .authorizeRequests()
            .anyRequest().authenticated();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(preauthAuthProvider());
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
        PreAuthenticatedAuthenticationProvider preauthAuthProvider =
            new PreAuthenticatedAuthenticationProvider();
                preauthAuthProvider.setPreAuthenticatedUserDetailsService(
                    userDetailsServiceWrapper());
        return preauthAuthProvider;
    }

    @Bean
    public OnlyRolesPreAuthenticatedUserDetailsService userDetailsServiceWrapper() {
        OnlyRolesPreAuthenticatedUserDetailsService service =
            new MyPreAuthenticatedUserDetailsService();
        return service;
    }

    @Bean
    public MyPreAuthenticatedProcessingFilter customAuthFilter() throws Exception {
        MyPreAuthenticatedProcessingFilter filter = new MyPreAuthenticatedProcessingFilter();
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }
}

我认为上面的代码是值得的,因为互联网上的示例非常基础,而 Spring 文档缺乏这样的细节。

于 2016-09-28T14:52:18.760 回答
19

是的,预认证方案正是您正在寻找的。

当主体已经在会话中时,似乎应该使用这些对象,这是由一些先前的身份验证机制提出的(对吗?)。

并非如此,您可以根据需要使用预身份验证PreAuthenticatedAuthenticationToken从请求中创建。只需做一些我在另一个问题中描述的事情

首先扩展AbstractPreAuthenticatedProcessingFilter以从请求中获取用户名和角色:

public class MyPreAuthenticatedProcessingFilter
    extends AbstractPreAuthenticatedProcessingFilter {

  public MyPreAuthenticatedProcessingFilter(
      AuthenticationManager authenticationManager) {
    setAuthenticationDetailsSource(new MyAuthenticationDetailsSource());
  }

  @Override
  protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
    return "Anonymous";
  }

  @Override
  protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
    return "N/A";
  }

  public static class MyAuthenticationDetailsSource implements 
      AuthenticationDetailsSource<HttpServletRequest, MySessionUserDetails> {
    // roles probably should be encrypted somehow
    static final String ROLES_PARAMETER = "pre_auth_roles";

    @Override
    public MySessionUserDetails buildDetails(HttpServletRequest req) {
      // create container for pre-auth data
      return new MySessionUserDetails(req.getParameter(ROLES_PARAMETER));
    }
  }
}

MySessionUserDetails类将带有角色的 spring 拆分为 List ofSimpleGrantedAuthority或任何其他GrantedAuthority实现。此外,建议使用 List 并且优于GrantedAuthority[].

二、实施AuthenticationUserDetailsService

public class MyPreAuthenticatedUserDetailsService implements 
    AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

  @Override
  public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
      throws UsernameNotFoundException {
    MySessionUserDetails sessionUserDetails =
        (MySessionUserDetails) token.getDetails();
    List<GrantedAuthority> authorities = sessionUserDetails.getAuthorities();
    return new User(token.getName(), "N/A", true, true, true, true, authorities);
  }
}

然后在您的 XML 中将块连接在一起:

<security:http use-expressions="true">
  <security:intercept-url pattern="/**" access="isAuthenticated()" />
  <security:custom-filter position="PRE_AUTH_FILTER"
      ref="myPreAuthenticationFilter" />
</security:http>

<bean id="myPreAuthenticationFilter"
    class="com.example.MyPreAuthenticatedProcessingFilter">
  <property name="authenticationManager" ref="authenticationManager" />
</bean>

<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
  <property name="preAuthenticatedUserDetailsService">
    <bean class="com.example.MyPreAuthenticatedUserDetailsService" />
  </property>
</bean>

<security:authentication-manager alias="authenticationManager">
  <security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>

瞧!您应该User在您的应用程序中使用经过身份验证的主体。

我在这里编写的代码需要 Spring Security 3.1,如果您要使用它,我强烈建议您使用它(它确实需要 Spring 3.0.7+)。此外,Spring Security 参考手册是您的朋友!

于 2012-09-18T18:04:37.087 回答