spring-security 在JwtAuthenticationFilter之前执行一次请求过滤器

yshpjwxd  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(271)

我有一个设置,我需要在其中进行租户感知的身份验证和授权。

  1. @Order(Ordered.LOWEST_PRECEDENCE - 100)
  2. public class TenantFilter extends OncePerRequestFilter {
  3. private static final Logger logger = LoggerFactory.getLogger(TenantFilter.class);
  4. private static final String TENANT_HEADER = "X-Tenant";
  5. private static final String CONNECTION_STRING = "ObfuscatedConnectionString";
  6. private static final String TENANT_REPLACEMENT = "TENANT";
  7. @Override
  8. protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
  9. String dbConnectionString = CONNECTION_STRING.replace(TENANT_REPLACEMENT, "");
  10. ConnectionStorage.setConnection(dbConnectionString);
  11. filterChain.doFilter(request, response);
  12. ConnectionStorage.clear();
  13. }
  14. }

虽然我知道有一些地方可以改进,但这只是一个占位符,以便能够测试该机制。2实际的实现将在后面进行。3当在不需要添加JWT的情况下进行测试时,它可以按预期工作,并且在给定正确的前提条件的情况下根据请求切换承租人。
但是,我不想在每个请求上都发送用户名+密码,而想在混合中添加一个JWT。

  1. public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
  2. private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
  3. private AuthenticationManager authenticationManager;
  4. public JwtAuthenticationFilter (AuthenticationManager authenticationManager) {
  5. this.authenticationManager = authenticationManager;
  6. }
  7. @Override
  8. public Authentication attemptAuthentication (HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
  9. logger.info("Attempting authentication");
  10. try {
  11. UserRequest creds = new ObjectMapper()
  12. .readValue(request.getInputStream(), UserRequest.class);
  13. return authenticationManager.authenticate(
  14. new UsernamePasswordAuthenticationToken(
  15. creds.getUsername(),
  16. creds.getPassword(),
  17. new ArrayList<>())
  18. );
  19. } catch (IOException e) {
  20. throw new RuntimeException(e);
  21. }
  22. }
  23. @Override
  24. protected void successfulAuthentication (HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
  25. logger.info("Authentication successful");
  26. String token = JWT.create()
  27. .withSubject(((User) auth.getPrincipal()).getUsername())
  28. .withExpiresAt(new Date(System.currentTimeMillis() + (JWTConstants.ACCESS_TOKEN_VALIDITY_SECONDS * 1000)))
  29. .sign(Algorithm.HMAC512(JWTConstants.SIGNING_KEY.getBytes()));
  30. response.addHeader(JWTConstants.HEADER_STRING, JWTConstants.TOKEN_PREFIX + token);
  31. }
  32. }

  1. public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
  2. private static final Logger logger = LoggerFactory.getLogger(JwtAuthorizationFilter.class);
  3. public JwtAuthorizationFilter (AuthenticationManager authenticationManager) {
  4. super(authenticationManager);
  5. }
  6. @Override
  7. protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
  8. logger.info("Doing filter internal");
  9. String header = request.getHeader(JWTConstants.HEADER_STRING);
  10. if (header == null || !header.startsWith(JWTConstants.TOKEN_PREFIX)) {
  11. chain.doFilter(request, response);
  12. return;
  13. }
  14. UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
  15. SecurityContextHolder.getContext().setAuthentication(authentication);
  16. chain.doFilter(request, response);
  17. }
  18. private UsernamePasswordAuthenticationToken getAuthentication (HttpServletRequest request) {
  19. String token = request.getHeader(JWTConstants.HEADER_STRING);
  20. if (token != null) {
  21. // parse the token.
  22. String user = JWT.require(Algorithm.HMAC512(JWTConstants.SIGNING_KEY.getBytes()))
  23. .build()
  24. .verify(token.replace(JWTConstants.TOKEN_PREFIX, ""))
  25. .getSubject();
  26. if (user != null) {
  27. return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
  28. }
  29. return null;
  30. }
  31. return null;
  32. }
  33. }

为我的请求提供身份验证。在/api/user/login中有一个用户名和密码,还有一个jwt标记用于其他所有内容。
然而,看起来好像首先执行安全过滤器,并且我的承租人过滤器对于设置要转到的正确DB的connectionstring相当重要。
版本:springframework。 Boot :2.6.2

7d7tgy0s

7d7tgy0s1#

你可以看看这个答案:https://stackoverflow.com/a/59340951这将使您能够最大限度地控制过滤器的执行时间。
我想(但我可能错了)@Order(Ordered.HIGHEST_PRECEDENCE)也可能会起作用。虽然措辞有点奇怪,但Ordered.HIGHEST_PRECEDENCE会给你Integer.MIN_VALUE,较低的值会先执行。
顺便说一句,在编写您自己的JWT验证过滤器之前,还请查看Spring Security的OAuth 2.0功能(除非您有特定的情况):https://docs.spring.io/spring-security/reference/6.0.0-M1/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-minimalconfiguration

相关问题