Здравствуйте, я пытаюсь мигрировать с аутентификации сессии Spring Security и авторизации AUTH через JWT. У меня есть вопрос относительно конкретной ситуации, с которой я столкнулся. Вместо того, чтобы использовать заголовок авторизации для аутентификации, я заинтересован в использовании файлов cookie, чтобы избежать хранения токена в локальном хранилище. Тем не менее, мой интеграционный тест продолжает проваливаться из -за отсутствия «токена носителя». Я хотел бы знать, столкнулся ли кто -нибудь еще с подобным сценарием, в котором им нужно было отправить токен JWT в качестве файлов cookie вместо использования заголовков авторизации. Если да, то как вы обратились к сообщению об ошибке, посмотрите ниже ? Любые понимание или решения будут высоко оценены. Спасибо. < /P>
ошибка
main] .s.r.w.a.BearerTokenAuthenticationFilter : Did not process request since did not find bearer token
Интеграционный тест
@Test
@Order(3)
void login() throws Exception {
MvcResult login = this.MOCK_MVC
.perform(post("******")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(new LoginDTO(ADMIN_EMAIL, ADMIN_PASSWORD).convertToJSON().toString())
)
.andExpect(status().isOk())
.andReturn();
Cookie cookie = login.getResponse().getCookie(COOKIE_NAME);
// Test route
this.MOCK_MVC
.perform(get("****").cookie(cookie))
.andExpect(status().isOk());
}
< /code>
Метод входа < /p>
/**
* Note Transactional annotation is used because Entity class has properties with fetch type LAZY
* @param dto consist of principal(username or email) and password.
* @param req of type HttpServletRequest
* @param res of type HttpServletResponse
* @throws AuthenticationException is thrown when credentials do not exist or bad credentials
* @return ResponseEntity of type HttpStatus
* */
@Transactional
public ResponseEntity login(LoginDTO dto, HttpServletRequest req, HttpServletResponse res) {
Authentication authentication = this.authManager.authenticate(
UsernamePasswordAuthenticationToken.unauthenticated(dto.getPrincipal(), dto.getPassword())
);
// Jwt Token
String token = this.jwtTokenService.generateToken(authentication);
// Add Jwt Cookie to Header
Cookie jwtCookie = new Cookie(COOKIENAME, token);
jwtCookie.setDomain(DOMAIN);
jwtCookie.setPath(COOKIE_PATH);
jwtCookie.setSecure(COOKIE_SECURE);
jwtCookie.setHttpOnly(HTTPONLY);
jwtCookie.setMaxAge(COOKIEMAXAGE);
// Add custom cookie to response
res.addCookie(jwtCookie);
// Second cookie where UI can access to validate if user is logged in
Cookie cookie = new Cookie(LOGGEDSESSION, UUID.randomUUID().toString());
cookie.setDomain(DOMAIN);
cookie.setPath(COOKIE_PATH);
cookie.setSecure(COOKIE_SECURE);
cookie.setHttpOnly(false);
cookie.setMaxAge(COOKIEMAXAGE);
// Add custom cookie to response
res.addCookie(cookie);
return new ResponseEntity(OK);
}
< /code>
FilterChain < /p>
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.cors(Customizer.withDefaults())
.authorizeHttpRequests(auth -> {
auth.requestMatchers(publicRoutes()).permitAll();
auth.anyRequest().authenticated();
})
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()))
.exceptionHandling((ex) -> ex.authenticationEntryPoint(this.authEntryPoint))
// .addFilterBefore(new JwtFilter(), BearerTokenAuthenticationFilter.class)
.logout(out -> out
.logoutUrl("****")
.deleteCookies(COOKIE_NAME, LOGGEDSESSION)
.logoutSuccessHandler((request, response, authentication) ->
SecurityContextHolder.clearContext()
)
)
.build();
}
< /code>
Наконец, я хочу привлечь ваше внимание на SecurityFilterChain, упомянутый ранее, где вы заметите, что я прокомментировал метод AddFilterbefore. Первоначально мой подход заключался в обработке каждого входящего запроса путем извлечения желаемого cookie, содержащего токен JWT, и добавление его в заголовки запроса. Этот подход работает хорошо, когда существует cookie, но не когда файл cookie является нулевым, например, во время процесса входа пользователя. Примечание HeadermapRequestWrapper реализация аналогична ссылке
@Component @Slf4j
public class JwtFilter extends OncePerRequestFilter {
@Value(value = "${server.servlet.session.cookie.name}")
private String COOKIENAME;
@Override
protected void doFilterInternal(
@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response,
@NotNull FilterChain filterChain
) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
log.info("Cookies Array " + Arrays.toString(cookies)); // Null on login requests
HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(request);
if (cookies != null) {
Optional cookie = Arrays.stream(cookies)
.map(Cookie::getName)
.filter(name -> name.equals(COOKIENAME))
.findFirst();
cookie.ifPresent(s -> requestWrapper.addHeader(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(s)));
}
filterChain.doFilter(requestWrapper, response);
}
}
Подробнее здесь: https://stackoverflow.com/questions/766 ... ion-header