无法在 Java Spring 引导/Angular 应用程序中获取 cookie
Cannot get cookies in Java Spring Boot / Angular application
我正在开发 Angular11 前端应用程序以及 Java Spring 引导后端。
上下文
我正在尝试使用 JWT 使用 cookie 创建身份验证。
为此,我受到
的启发
- JWT refresh token flow
我的端点 /authenticate
returns 一个 jwt 访问令牌并在 cookie 中设置一个 jwt 刷新令牌 (httpOnly)。
我的端点 /refreshtoken
从 cookie 中获取刷新令牌并在生成新的 jwt 访问令牌和新的 jwt 刷新令牌之前对其进行验证。
这是我的 AuthenticationController
的代码
@RestController
@AllArgsConstructor
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
public class AuthenticationController {
private final AuthenticationManager authenticationManager;
private final JwtTokenUtil jwtTokenUtil;
private final UserDetailsServiceImpl userDetailsService;
private final static String REFRESH_TOKEN_COOKIE = "resfreshtoken";
@PostMapping(value = "/authenticate")
public ResponseEntity<JwtAuthenticationResponse> createAuthenticationToken(@RequestBody JwtAuthenticationRequest authenticationRequest, HttpServletResponse response) throws Exception {
try {
this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword()));
}
catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
}
catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
final UserDetails userDetails = this.userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
final String token = this.jwtTokenUtil.generateToken(userDetails.getUsername());
final String refreshToken = this.jwtTokenUtil.generateRefreshToken(new HashMap<>(), userDetails.getUsername());
Cookie cookie = new Cookie(REFRESH_TOKEN_COOKIE, refreshToken);
cookie.setHttpOnly(true);
// cookie.setDomain("localhost");
// cookie.setPath("/");
response.addCookie(cookie);
return ResponseEntity.ok(new JwtAuthenticationResponse(token));
}
@GetMapping(value = "/refreshtoken")
public ResponseEntity<?> refreshToken(@CookieValue(value = REFRESH_TOKEN_COOKIE, required = false) String refreshToken, HttpServletRequest request, HttpServletResponse response) {
Cookie[] cookies = request.getCookies(); // ALWAYS returns null
log.debug("refreshToken {}", refreshToken); // ALWAYS null
try {
Claims claims = this.jwtTokenUtil.getAllClaimsFromToken(refreshToken);
final String username = claims.get("sub").toString();
final String newAccessToken = this.jwtTokenUtil.generateToken(username);
final String newRefreshToken = this.jwtTokenUtil.generateRefreshToken(claims, username);
CookieUtil.writeCookie(response, REFRESH_TOKEN_COOKIE, newRefreshToken);
return ResponseEntity.ok(new JwtAuthenticationResponse(newAccessToken));
}
catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
throw new BadCredentialsException("INVALID_CREDENTIALS", ex);
}
catch (ExpiredJwtException e) {
// user should re-login
}
return new ResponseEntity<>("Something went wrong", HttpStatus.BAD_REQUEST);
}
}
在 Angular 前端,这是我添加到我的 /refreshtoken Http 请求的选项 (withCredentials=true
)
refreshToken(): Observable<AuthenticationResponse> {
return this.http.get<AuthenticationResponse>(this.apiUrl + 'refreshtoken', { withCredentials: true }).pipe(
tap(response => LocalStorageUtils.save(LocalStorageKey.JWT_ACCESS_TOKEN_KEY, response.jwtAccessToken))
);
}
我的问题
如果我尝试到达我的端点 /authenticate
然后从邮递员 /refreshtoken
,一切正常,我可以看到 cookie
如果我从前端调用 /authenticate
,我可以在 header SET-COOKIE 的响应中看到 cookie(在 cookies 选项卡中)
但是如果我从我的前端调用 /refreshtoken
,我就无法在后端使用 request.getCookies()
或 @CookieValue()
获取 cookie, 它总是 returns null !
前端似乎很好地接收了 cookie,但没有设置(我在 application 选项卡 -> Chrome 上的 cookie 中看不到它)。
因此它不与 /refreshtoken 请求一起发送
如果有人可以提供帮助或知道出了什么问题,我将不胜感激!如果需要,我可以提供有关我的代码的更多详细信息。
您需要将 withCredentials: true
添加到您的 httpOptions
并在每个请求中将其与 HttpClient
一起传递。您还可以使用 HttpClient 和 Interceptors 对其进行全局配置。
正如@TCH 提到的,对于 API 其中 returns Set-Cookie header 我们需要设置请求 header 和 withCredentials: true
.我也犯了类似的错误,我想强调这一点:-)
我正在开发 Angular11 前端应用程序以及 Java Spring 引导后端。
上下文
我正在尝试使用 JWT 使用 cookie 创建身份验证。 为此,我受到
的启发- JWT refresh token flow
我的端点 /authenticate
returns 一个 jwt 访问令牌并在 cookie 中设置一个 jwt 刷新令牌 (httpOnly)。
我的端点 /refreshtoken
从 cookie 中获取刷新令牌并在生成新的 jwt 访问令牌和新的 jwt 刷新令牌之前对其进行验证。
这是我的 AuthenticationController
@RestController
@AllArgsConstructor
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
public class AuthenticationController {
private final AuthenticationManager authenticationManager;
private final JwtTokenUtil jwtTokenUtil;
private final UserDetailsServiceImpl userDetailsService;
private final static String REFRESH_TOKEN_COOKIE = "resfreshtoken";
@PostMapping(value = "/authenticate")
public ResponseEntity<JwtAuthenticationResponse> createAuthenticationToken(@RequestBody JwtAuthenticationRequest authenticationRequest, HttpServletResponse response) throws Exception {
try {
this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword()));
}
catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
}
catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
final UserDetails userDetails = this.userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
final String token = this.jwtTokenUtil.generateToken(userDetails.getUsername());
final String refreshToken = this.jwtTokenUtil.generateRefreshToken(new HashMap<>(), userDetails.getUsername());
Cookie cookie = new Cookie(REFRESH_TOKEN_COOKIE, refreshToken);
cookie.setHttpOnly(true);
// cookie.setDomain("localhost");
// cookie.setPath("/");
response.addCookie(cookie);
return ResponseEntity.ok(new JwtAuthenticationResponse(token));
}
@GetMapping(value = "/refreshtoken")
public ResponseEntity<?> refreshToken(@CookieValue(value = REFRESH_TOKEN_COOKIE, required = false) String refreshToken, HttpServletRequest request, HttpServletResponse response) {
Cookie[] cookies = request.getCookies(); // ALWAYS returns null
log.debug("refreshToken {}", refreshToken); // ALWAYS null
try {
Claims claims = this.jwtTokenUtil.getAllClaimsFromToken(refreshToken);
final String username = claims.get("sub").toString();
final String newAccessToken = this.jwtTokenUtil.generateToken(username);
final String newRefreshToken = this.jwtTokenUtil.generateRefreshToken(claims, username);
CookieUtil.writeCookie(response, REFRESH_TOKEN_COOKIE, newRefreshToken);
return ResponseEntity.ok(new JwtAuthenticationResponse(newAccessToken));
}
catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
throw new BadCredentialsException("INVALID_CREDENTIALS", ex);
}
catch (ExpiredJwtException e) {
// user should re-login
}
return new ResponseEntity<>("Something went wrong", HttpStatus.BAD_REQUEST);
}
}
在 Angular 前端,这是我添加到我的 /refreshtoken Http 请求的选项 (withCredentials=true
)
refreshToken(): Observable<AuthenticationResponse> {
return this.http.get<AuthenticationResponse>(this.apiUrl + 'refreshtoken', { withCredentials: true }).pipe(
tap(response => LocalStorageUtils.save(LocalStorageKey.JWT_ACCESS_TOKEN_KEY, response.jwtAccessToken))
);
}
我的问题
如果我尝试到达我的端点 /authenticate
然后从邮递员 /refreshtoken
,一切正常,我可以看到 cookie
如果我从前端调用 /authenticate
,我可以在 header SET-COOKIE 的响应中看到 cookie(在 cookies 选项卡中)
/refreshtoken
,我就无法在后端使用 request.getCookies()
或 @CookieValue()
获取 cookie, 它总是 returns null !
前端似乎很好地接收了 cookie,但没有设置(我在 application 选项卡 -> Chrome 上的 cookie 中看不到它)。
因此它不与 /refreshtoken 请求一起发送
如果有人可以提供帮助或知道出了什么问题,我将不胜感激!如果需要,我可以提供有关我的代码的更多详细信息。
您需要将 withCredentials: true
添加到您的 httpOptions
并在每个请求中将其与 HttpClient
一起传递。您还可以使用 HttpClient 和 Interceptors 对其进行全局配置。
正如@TCH 提到的,对于 API 其中 returns Set-Cookie header 我们需要设置请求 header 和 withCredentials: true
.我也犯了类似的错误,我想强调这一点:-)