我正在寻找帮助在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令牌或会话令牌,用户可以直接调用任何端点。这些请求永远不应生成会话令牌。
哪个配置错误或我如何实现这些方案?
谢谢!