为什么 Java 中的 JWT 令牌无效或过期时,我的 CustomAuthenticationEntryPoint 开始方法没有被调用?

lil*_*hit 3 java spring-security jwt spring-resource-server

当 jwt 令牌无效或过期时,为什么不调用此开始方法?当令牌为空时会调用它。奇怪的是,在调试时我发现当令牌无效或过期时,会调用 BearerTokenAuthenticationEntryPoint.commence() 方法。这个类是标准java库的一部分,并且是最终的,所以不能扩展。但它实现了与我实现相同的接口 - AuthenticationEntryPoint,但我的开始方法仍然没有被调用。仅当令牌为空时才会调用它。

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
  public CustomAuthenticationEntryPoint() {
  }

  @Override
  public void commence(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException authenticationException) throws IOException {
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    HttpStatus status = HttpStatus.UNAUTHORIZED;

    final Map<String, Object> body = new HashMap<>();
    body.put("status", status.name());
    body.put("statusCode", status.value());
    body.put("message", "You need to login first in order to perform this action");

    final ObjectMapper mapper = new ObjectMapper();
    mapper.writeValue(response.getOutputStream(), body);
  }
}
Run Code Online (Sandbox Code Playgroud)

我这样使用它:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests((authorize) -> authorize
                .requestMatchers("/api/v1/auth/**").permitAll() 
                .requestMatchers("/api/v1/admin/**").hasAuthority(Authority.ADMIN.name())
                .anyRequest().authenticated()
            )
        .csrf().disable()
        .cors().disable()
        .httpBasic().disable()
        .oauth2ResourceServer((oauth2) ->
            oauth2.jwt((jwt) -> jwt.jwtAuthenticationConverter(jwtToUserConverter))
        )
        .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .exceptionHandling((exceptions) -> exceptions
            .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
            .accessDeniedHandler(new CustomAccessDeniedHandler())
        );
    return http.build();
}
Run Code Online (Sandbox Code Playgroud)

我尝试实现 AuthenticationEntryPoint 并期望在令牌无效或过期时调用我的start() 方法。但我的 begin() 方法没有被调用,而是 BearerTokenAuthenticationEntryPoint.commence() 方法被调用。

这是我的 JwtToUserConverter:

@Component
public class JwtToUserConverter implements Converter<Jwt, UsernamePasswordAuthenticationToken> {
    @Override
    public UsernamePasswordAuthenticationToken convert(Jwt jwt) {
        // extract user information from the JWT
        String username = jwt.getSubject();
        List<LinkedTreeMap> authoritiesList = jwt.getClaim("authorities");

        // create a collection of SimpleGrantedAuthority objects
        Collection<SimpleGrantedAuthority> grantedAuthorities = authoritiesList.stream()
            .map(authority -> new SimpleGrantedAuthority((String) authority.get("role")))
            .collect(Collectors.toList());

        // create the UsernamePasswordAuthenticationToken
        return new UsernamePasswordAuthenticationToken(username, null, grantedAuthorities);
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我传递无效令牌时的完整调试日志:

"http-nio-4983-exec-2@10996" daemon prio=5 tid=0x1b nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint.commence(BearerTokenAuthenticationEntryPoint.java:63)
      at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.lambda$new$0(BearerTokenAuthenticationFilter.java:77)
      at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter$$Lambda$1321/0x00000008014cfaf8.commence(Unknown Source:-1)
      at org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler.onAuthenticationFailure(AuthenticationEntryPointFailureHandler.java:55)
      at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:150)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
      at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
      at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
      at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
      at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
      at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
      at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
      at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
      at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
      at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
      at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
      at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
      at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
      at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
      at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
      at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
      at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400)
      at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
      at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859)
      at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734)
      at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-1@10995" daemon prio=5 tid=0x1a nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-3@10997" daemon prio=5 tid=0x1c nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-4@10998" daemon prio=5 tid=0x1d nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-5@10999" daemon prio=5 tid=0x1e nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-6@11000" daemon prio=5 tid=0x1f nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-7@11001" daemon prio=5 tid=0x20 nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-8@11002" daemon prio=5 tid=0x21 nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-9@11003" daemon prio=5 tid=0x22 nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:341)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(AbstractQueuedSynchronizer.java:506)
      at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1623)
      at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:435)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:117)
      at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:33)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1114)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:833)

"http-nio-4983-exec-10@11004" daemon prio=5 tid=0x23 nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      a

Mar*_*gio 5

根据您的日志,BearerAuthenticationEntryPoint正在从第 77行调用:

at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.lambda$new$0(BearerTokenAuthenticationFilter.java:77)
Run Code Online (Sandbox Code Playgroud)

这是该authenticationFailureHandler字段,然后调用AuthenticationEntryPoint. 如果我没记错的话,oauth2ResourceServerDSL 不会使用相同的AuthenticationEntryPointfrom exceptionHandling(),因此您必须显式配置它,如下所示:

at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.lambda$new$0(BearerTokenAuthenticationFilter.java:77)
Run Code Online (Sandbox Code Playgroud)