АутентификацияCredentialsNotFoundException с защитой метода с использованием аутентификации jwt

#spring-boot #kotlin #spring-security #jwt

Вопрос:

Я следовал этому руководству, чтобы получить аутентификацию на основе jwt в моем приложении spring boot: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security Однако я использую Kotlin.

Согласно учебнику, я добавил a TokenAuthenticationFilter , который распространяется AbstractAuthenticationProcessingFilter на цепочку фильтров в WebSecurityConfigurerAdapter .

     override fun configure(http: HttpSecurity) = http.apply {
        //...
        authenticationProvider(authProvider)
        addFilterBefore(tokenAuthFilter, SecurityContextHolderAwareRequestFilter::class.java)
        //...
 

В successfulAuthentication методе этот фильтр правильно установит учетные данные:

     SecurityContextHolder.getContext().setAuthentication(authResult);
 

Цепочка фильтров выполняется для методов в контроллерах без защиты методов.
Вход в систему работает, я получаю токен jwt, и когда я помещаю его в заголовок авторизации запросов, я получаю надлежащую аутентификацию, поэтому тестирование с конечной точкой я успешно возвращаю вошедшего пользователя

     @GetMapping("/")
    fun whoami(@AuthenticationPrincipal user: User?) = user;
 

Однако, как только я попытаюсь использовать безопасность метода на какой-либо конечной точке

     @PostMapping("/upload")
    @PreAuthorize("hasAuthority('UploadArtifact')")
    fun uploadArtifact(
        @RequestParam("artifact", required = true) artifact: MultipartFile,
        @Valid @RequestParam("meta", required = true) request: UploadArtifactRequest
    ): ResponseEntity<Any> {
    //...
 

Я получаю исключение authenticationкредитальснотпоиск

организация.каркасная работа.безопасность.аутентификация.Исключение AuthenticationCredentialsNotFoundException: Объект проверки подлинности не был найден в контексте безопасности в org.springframework.security.access.intercept.AbstractSecurityInterceptor.Учетные данные не найдены(AbstractSecurityInterceptor.java:333) ~[spring-security-core-5.5.0.jar:5.5.0] в организации. springframework.безопасность.доступ.перехват.AbstractSecurityInterceptor.Перед вызовом(AbstractSecurityInterceptor.java:200) ~[spring-security-core-5.5.0.jar:5.5.0] в организации.каркасная работа.безопасность.доступ.перехват.альянс.MethodSecurityInterceptor.вызовите(MethodSecurityInterceptor.java:58) ~[spring-security-core-5.5.0.jar:5.5.0] в org.springframework.aop.framework.Рефлексивный метод вызова.продолжайте(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8] в org.springframework.aop.framework.Cglibopproxy$Вызов cglibmethod.продолжайте(CglibEopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8] в org.springframework.aop.framework.CglibEopProxy$DynamicAdvisedInterceptor.перехватить(CglibEopProxy.java:692) ~[spring-aop-5.3.8.jar:5.3.8] в [###имя пакета отредактировано###].ArtifactController$$EnhancerBySpringCGLIB$$99d39dee.uploadArtifact() ~[main/:na] …

I set breakpoints

  • at the start of the TokenAuthenticationFilter.successfulAuthentication method.
  • in ApplicationFilterChain.doFilter

Apparently two ApplicationFilterChain instances run on the request, both of which containa delegating proxy chain named ‘springSecurityFilterChain’

  1. The ApplicationFilterChain that is executed first is started from StandardWrapperValve.java .
    Its springSecurityFilterChain does not contain the TokenAuthenticationFilter . The AuthenticationCredentialsNotFoundException exception is thrown here.
  2. The second ApplicationFilterChain is started from ApplicationDispatcher.java .
    Its springSecurityFilterChain does contain the TokenAuthenticationFilter and successfulAuthentication is reached, but that is obviousely useless at that point.

So now I have two independent questions:

  • Как я могу гарантировать, что аутентификация произойдет вовремя? Должны ли быть две цепочки фильтров — или я что-то напутал с настройкой?
  • в целом: должен ли я вообще использовать такой учебник — или есть лучший способ интегрировать проверку подлинности без сохранения состояния с jwt в 2021 году в приложение spring boot?