spring - Spring Security Filter 如何与自定义身份验证一起工作以及如何将其与 Servlet Filter 结合使用?
问题描述
所以我有一个关于 Spring Security 的问题。因此,我想使用自定义标头检查身份验证,然后我想检查自定义标头中给出的令牌到 redis 值,并将数据对象设置为抽象身份验证令牌的自定义实现中的凭据。我已经按照这个网站的教程:https ://shout.setfive.com/2015/11/02/spring-boot-authentication-with-custom-http-header/ ,但我无法更新认证界面在 SecurityContextHolder.getContext() 中(我在身份验证接口的实现中设置了凭据,但是当我在服务中获取它时,凭据为空)。
我还发现了其他问题,我实际上想像这样订购过滤器:
ExceptionHandlerFilter (to catch exception error in the filter) -> Other filter or CustomWebSecurityConfigurerAdapter.
但是当 url 匹配到 antMatcher 时,我发现 ExceptionHandlerFilter 被应用程序跳过了。
我对此感到非常困惑,找不到更好的使用 Spring Security 实现自定义身份验证的教程。所以我想问一下你们能不能告诉我Spring Security是如何工作的,以及如何将它与Filter结合起来?
这是我第一个捕获异常的过滤器
@Component
@Order(0)
public class ExceptionHandlerFilter extends OncePerRequestFilter {
private JaminExceptionHandler exceptionHandler;
private ObjectMapper objectMapper = new ObjectMapper();
@Autowired
public ExceptionHandlerFilter(JaminExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (Throwable exception) {
ResponseEntity<?> responseEntity = this.exceptionHandler.handleException(exception, request);
response.setStatus(responseEntity.getStatusCode().value());
response.setHeader("Content-Type", "application/json");
response.getWriter().write(this.objectMapper.writeValueAsString(responseEntity.getBody()));
}
}
}
这是我的身份验证过滤器
@Component
public class AuthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("J-Auth");
if (token != null) {
Authentication auth = new JaminAuthenticationToken(token);
SecurityContextHolder.getContext().setAuthentication(auth);
filterChain.doFilter(request, response);
} else {
throw new JaminException("Not authorized", JaminExceptionType.NOT_AUTHORIZED, HttpStatus.UNAUTHORIZED);
}
}
}
身份验证提供程序
@Component
public class JaminAuthenticationProvider implements AuthenticationProvider {
private RedisTemplate<String, String> authRedis;
private ObjectMapper objectMapper = new ObjectMapper();
@Autowired
public JaminAuthenticationProvider(@Qualifier("authRedis") RedisTemplate<String, String> authRedis) {
this.authRedis = authRedis;
}
private UserDTO getUserDTO(String token) throws IOException {
String userData = this.authRedis.opsForValue().get(token);
if (userData == null) {
throw new JaminException("Not authorized", JaminExceptionType.NOT_AUTHORIZED, HttpStatus.UNAUTHORIZED);
}
return this.objectMapper.readValue(userData, UserDTO.class);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
JaminAuthenticationToken auth = (JaminAuthenticationToken) authentication;
try {
UserDTO userDTO = this.getUserDTO(auth.getToken());
auth.setCredentials(userDTO);
return auth;
} catch (IOException e) {
e.printStackTrace();
}
throw new JaminException("Not authorized", JaminExceptionType.NOT_AUTHORIZED, HttpStatus.UNAUTHORIZED);
}
@Override
public boolean supports(Class<?> authentication) {
return JaminAuthenticationToken.class.isAssignableFrom(authentication);
}
}
WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
@Order(1)
public class JaminSecurityAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private JaminAuthenticationProvider jaminAuthenticationProvider;
private void disableDefaultSecurity(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.csrf().disable();
http.formLogin().disable();
http.logout().disable();
http.httpBasic().disable();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
this.disableDefaultSecurity(http);
http.antMatcher("/auth/check")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(new AuthFilter(), BasicAuthenticationFilter.class);
// http.authorizeRequests().anyRequest().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(jaminAuthenticationProvider);
}
}
解决方案
Spring Security 有一些“之前和之后”的步骤。有一些处理程序可以提供帮助。我不知道你的代码,但如果你能获得你的身份验证,也许你只需要扩展一个 SuccessHandler 并在那里设置身份验证,就像我在我的博客项目中所做的那样:
if(checkEmail(authentication)) {
val adminRole = SimpleGrantedAuthority("ROLE_ADMIN")
val oldAuthorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities()
val updateAuthorities = mutableListOf<GrantedAuthority>()
updateAuthorities.add(adminRole)
updateAuthorities.addAll(oldAuthorities)
SecurityContextHolder.getContext().setAuthentication(UsernamePasswordAuthenticationToken(authentication.getPrincipal(),
authentication.getCredentials(),
updateAuthorities))
}
关于过滤器,也许您可以在这里找到答案。我不喜欢使用过滤器和拦截器,但有时它们确实是必要的。
推荐阅读
- php - Tinymce 和 n1ed 和 codeigniter - 无法集成文件管理器
- java - 如何在 Spring 框架中正确访问环境变量?
- scala - 如何在 Intellij IDEA 中调试 flink 流作业
- android - 在 Android Studio 中以红色突出显示的文件
- python - 我无法让这个简单的 python 代码工作?
- string - 如何验证字符串列表是否仅包含数字字符?
- python - 使用 Python 从特定行开始读取和解析 HTML 文件
- sql - SQL 查询没有返回正确的结果 - SQLite
- python - 如何在索引0中初始化数据框的几列
- javascript - 如何将 CSS 过滤器应用于 drawImage()?