Redis中的Spring安全性和会话

时间:2017-08-29 19:36:44

标签: java spring authentication spring-boot spring-security

我正在寻找帮助在redis中配置Spring Security和Spring Session。基本上我需要用各种方法保护不同的端点。

1)我有端点/security/login(生成会话令牌)和/security/logout(使会话令牌无效)没有保护。

2)我的所有端点都以/ api / **开头,它必须具有保护功能,并且只能使用先前生成的会话令牌(x-auth-token)。

3)任何其他请求必须具有用户/密码的基本http保护。

仅当用户通过标头中的令牌JWT,cookie或特定自定义公司令牌(SSO)传递身份验证时,

/security/login才能创建有效的会话令牌。

对于这个提议我创建了:

1)Spring Security Class config:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Configuration
    @Order(1)
    public static class MainAPISecurityConfig extends WebSecurityConfigurerAdapter {

        @Autowired
        private AuthFilter authFilter;

        @Autowired
        private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/api/**") //all api requests is muts be auth with token
                    .hasAuthority("ROLE_USER")
                    .and()
                    .requestCache()
                    .requestCache(new NullRequestCache())
                    .and()
                    .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
                    .exceptionHandling()
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }
    }

    @Configuration
    @Order(2)
    public static class OtherRequestSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers( "/security/logout", "/security/login")
                    .permitAll()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .requestCache()
                    .requestCache(new NullRequestCache())
                    .and()
                    .httpBasic()
                    .and()
                    .csrf().disable()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        }
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

2)身份验证过滤器拦截用户凭据并将其注入安全上下文:

@Component
public class AuthFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        try {

            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
            String ssoToken = httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION);

            if(StringUtils.hasText(ssoToken)){
                TokenSSOAuth tokenSSOAuth = new TokenSSOAuth(ssoToken);
                SecurityContextHolder.getContext().setAuthentication(tokenSSOAuth);
            }

            filterChain.doFilter(servletRequest, servletResponse);

        } catch (Exception e) {
            log.error("AuthFilter ERROR: {}, MESSAGE: {}", e, e.getMessage());
        }
    }

    @Override
    public void destroy() {

    }

}

3)3个类,每个类用于实现Authentication接口的特定认证方法,其中之一是:

public class TokenSSOAuth implements Authentication {

    private final String tokenSSO;

    public TokenSSOAuth(String tokenSSO) {
        this.tokenSSO = tokenSSO;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public Object getCredentials() {
        return tokenSSO;
    }

    @Override
    public Object getDetails() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }

    @Override
    public boolean isAuthenticated() {
        return false;
    }

    @Override
    public void setAuthenticated(boolean b) throws IllegalArgumentException {

    }

    @Override
    public String getName() {
        return tokenSSO;
    }
}

4)自定义身份验证提供程序:

@Component
public class AppAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String tokenBks = (String) authentication.getCredentials();

        if ("fakeSSOToken".equals(tokenBks)) {
            LdapUserDto ldapUserDto = new LdapUserDto();
            ldapUserDto.setName("TEST USER SSO");

            return new UserAuthenticatedProfile(ldapUserDto);
        } else {
            throw new BadCredentialsException("Failed to validate user credentials");
        }

    }

    @Override
    public boolean supports(Class<?> aClass) {
        return aClass.equals(TokenSSOAuth.class);
    }

}

5)实现身份验证的类,如果用户通过身份验证,则包含来自LDAP的用户信息:

public class UserAuthenticatedProfile implements Authentication {

    private final LdapUserDto userProfile;

    public UserAuthenticatedProfile(LdapUserDto userProfile) {
        this.userProfile = userProfile;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getDetails() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }

    @Override
    public boolean isAuthenticated() {
        return true;
    }

    @Override
    public void setAuthenticated(boolean b) throws IllegalArgumentException {

    }

    @Override
    public String getName() {
        return userProfile.getName();
    }
}

逻辑:

1场景 - 从有角度的网站,用户首先需要调用/ security / login获取会话x-auth-token(持续时间为8小时),然后可以在应用程序的任何端点上使用8小时。本次会议春季将以redis形式进行共享提议。

2场景 - 如果拥有有效的JWT令牌或会话令牌,用户可以直接调用任何端点。这些请求永远不应生成会话令牌。

哪个配置错误或我如何实现这些方案?

谢谢!

0 个答案:

没有答案