您好,我正在尝试通过JWT从Spring Security Session身份验证和授权迁移到auth。我有一个关于我遇到的具体情况的问题。我不使用Authorization头进行身份验证,而是对使用cookie来避免将令牌存储在本地存储中感兴趣。然而,我的集成测试一直失败,因为没有一个“承载令牌”。我想知道是否有人遇到过类似的情况,他们需要发送JWT令牌作为cookie,而不是使用授权头。如果是,您如何解决错误消息look below
?任何见解或解决方案将不胜感激。- 谢谢你-谢谢
错误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());
}
字符串
登录方式
/**
* 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);
}
型
过滤链
@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();
}
型
最后,我想提请您注意前面提到的SecurityFilterChain,您会注意到我已经注解掉了addFilterBefore方法。最初,我的方法是通过提取包含JWT令牌的所需cookie并将其添加到请求头来处理每个传入请求。这种方法在cookie存在时工作良好,但在cookie为空时(例如,在用户登录过程中)工作不佳。注意HeaderMapRequestWrapper
的实现类似于link
@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<String> 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);
}
}
型
1条答案
按热度按时间ct3nt3jp1#
我可以通过查看spring docs来解决这个问题。由于默认情况下,资源服务器在Authorization头中查找承载令牌,并且在我的情况下,我作为cookie发送,因此我必须定义
BearerTokenResolver
的自定义实现。豆子
字符串
自定义实施
型