春季安全过滤器问题

问题描述 投票:0回答:1

使用Boot 2.1.14.Release / security 5.1.10

我有以下需要指定安全性的端点

/token/exchange-仅当请求具有Okta JWT时,此端点才应允许访问。它返回我已经通过JJWT手动创建的自定义JWT。基本上,用户将无需通过用户凭据,而已通过Okta进行了身份验证,并将提供该令牌作为其凭据。

我添加了Okta入门程序,并且按预期方式运行


/api/**-/api下的任何端点都需要我的自定义JWT在Authorization标头中


我具有以下安全配置:

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@Configuration
public class AppWebSecurityConfigurerAdapter {

    @Configuration
    @Order(1)
    public static class OktaWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/token/exchange") <------- this should "pin" this config right?
                    .authorizeRequests()
                    .antMatchers("/token/exchange").authenticated() <--- is this needed?
                    .and()
                    .oauth2ResourceServer().jwt();
            http.cors();
            http.csrf().disable();
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            Okta.configureResourceServer401ResponseBody(http);
        }
    }

    @Configuration
    @Order(2)
    @RequiredArgsConstructor
    public static class ApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        private final CustomSecurityConfig customSecurityConfig; <--- JWT secret key in here
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/api/**")
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .addFilter(new JwtFilter(authenticationManager(), customSecurityConfig))
                    .csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .cors();
        }
    }
}

及以下JwtFilter

@Slf4j
public class JwtFilter extends BasicAuthenticationFilter {

    private final CustomSecurityConfig customSecurityConfig;

    public JwtFilter(AuthenticationManager authenticationManager, CustomSecurityConfig customSecurityConfig) {
        super(authenticationManager);
        this.customSecurityConfig = customSecurityConfig;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        try {
            UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
            if (authentication == null) {
                chain.doFilter(request, response);
                return;
            }
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } catch (Exception exception){
            log.error("API authentication failed", exception);
            SecurityContextHolder.clearContext();
        }
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = new DefaultBearerTokenResolver().resolve(request);
        if (token == null) {
            return null;
        }
        Algorithm algorithm = Algorithm.HMAC256(customSecurityConfig.getSecret());
        JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer(CustomSecurityConfig.ISSUER)
                .build();
        DecodedJWT jwt = verifier.verify(token);
        return new UsernamePasswordAuthenticationToken(
                jwt.getClaim("user_name").asString(),
                null,
                jwt.getClaim("authorities")
                        .asList(String.class)
                        .stream()
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toList()));
    }
}

我的/api调用所有返回401及其返回,因为它们是由BearerTokenAuthenticationFilter(由我的OktaWebSecurityConfigurerAdapter使用)而不是我的JwtFilter处理的。自然,两个令牌之间的签名不匹配。我很困惑为什么我的/api调用甚至被该过滤器处理,因为我只为Okta处理程序应用了.oauth2ResourceServer().jwt();配置

我的日志看起来像这样:

SecurityContextHolder now cleared, as request processing completed
Checking match of request : '/api/entities'; against '/token/exchange'
Checking match of request : '/api/entities'; against '/api/**'
/api/entities at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
/api/entities at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
/api/entities at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
/api/entities at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
/api/entities at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
Trying to match using Ant [pattern='/logout', GET]
Checking match of request : '/api/entities'; against '/logout'
Trying to match using Ant [pattern='/logout', POST]
Request 'GET /api/entities' doesn't match 'POST /logout'
Trying to match using Ant [pattern='/logout', PUT]
Request 'GET /api/entities' doesn't match 'PUT /logout'
Trying to match using Ant [pattern='/logout', DELETE]
Request 'GET /api/entities' doesn't match 'DELETE /logout'
No matches found
/api/entities at position 6 of 13 in additional filter chain; firing Filter: 'BearerTokenAuthenticationFilter'
Authentication attempt using org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider
No event was found for the exception org.springframework.security.oauth2.core.OAuth2AuthenticationException
Authentication request for failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: An error occurred while attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@13691de5
SecurityContextHolder now cleared, as request processing completed

我一直都在用这种方法日夜不停地敲击……。谢谢您的帮助!

spring-boot spring-security jwt spring-security-oauth2
1个回答
0
投票

我将从您问题的答案开始(我认为)。您要使用addFilter(...)添加过滤器,但未指定任何订单信息。请改用addFilterBefore(...)

我会提醒您不要将JWT用于某种会话令牌,除非有一种方法可以撤销它们。 https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens

在您的情况下,听起来您可能正在将一个令牌交换为一个“较弱”的令牌。您可以采取一些措施来减轻这种风险,例如限制令牌的有效期限等。我没有用例的全部内容或使用方式,因此请仔细考虑盐:)

© www.soinside.com 2019 - 2024. All rights reserved.