大家好,我试图使用仅 HTTP 的 cookie 来保护我的 Spring Boot 应用程序,从本地存储迁移,我遇到了一些甚至 chatGPT 也无法解决的问题:)
首先,这是我的 CookieUtil 类
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
public class CookieUtil {
public static void create(HttpServletResponse httpServletResponse, String name, String value, Integer maxAge) {
Cookie cookie = new Cookie(name, value);
cookie.setSecure(false);
cookie.setHttpOnly(true);
cookie.setMaxAge(maxAge);
cookie.setPath("/");
cookie.setDomain("localhost");
httpServletResponse.addCookie(cookie);
}
public static void clear(HttpServletResponse httpServletResponse, String name) {
Cookie cookie = new Cookie(name, null);
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(0);
httpServletResponse.addCookie(cookie);
}
}
我尝试将 HttpOnly 设置为 false 以查看令牌是否在浏览器中设置,但仍然没有显示相同的内容,我知道当我设置为仅 HTTP 时它不应该显示 我知道 setSecure 只是为了本地开发
这是我的登录方法
public AccessTokenResponse signIn(LoginDto loginDto) {
AccessTokenResponse accessTokenResponse = authorizations.signIn(loginDto);
String jwt= accessTokenResponse.getToken();
int maxAge= (int)accessTokenResponse.getExpiresIn();
CookieUtil.create(response, "accessToken", jwt, maxAge);
return accessTokenResponse;
}
我使用 keycloak 作为赔偿管理器,我得到了很好的令牌,如下图所示 这是请求标头,您可以看到设置的 cookie 就在那里,(当我登录时,浏览器中也有同样的事情,我得到了设置的 cookie 标头)
这就是它在开发工具中的样子
现在的问题是从 accessToken 获取员工 By Keycloak
@GetMapping("/employee")
public ResponseEntity<EmployeeDto> getEmployeeByKeycloakId(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
String token = null;
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("accessToken")) {
token = cookie.getValue();
break;
}
}
}
if (token == null) {
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
String userid= tokenService.getUserIdFromToken(token);
return new ResponseEntity<>(
employeeMapper.toEmployee(this.employeeUseCases.getByKeycloakId(userid)),
HttpStatus.OK
);
}
如您所见,我正在尝试获取 cookie accessToken 来对其进行解码并获取 userId(顺便说一句,解码部分工作正常)此方法总是失败的原因是因为 cookie 始终为 null 意味着浏览器没有将它们发送到服务器
说到前面的代码,这是我的登录信息
signIn(user: User, rememberMe: boolean): Observable<any> {
return this._httpClient.post(`${this._apiUrl}/login`, user).pipe(
switchMap((response: any) => {
if (response.access_token) {
if(rememberMe){
this._storageService.setItem('rememberMe', JSON.stringify(rememberMe));
}
}
this._authenticated = true;
return this._userService.get();
})
);
}
这是应该添加令牌的标志部分
这就是获取员工的终点
get(): any {
return this._httpClient
.get<User>(`${this._apiUrl}/employee`, { withCredentials: true })
.pipe(
tap((user) => {
console.log(user)
this._user.next(user);
})
);
}
如你所见,我使用 withCredentials:true
说到cors,我的控制器中已经有了这个
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
@RestController
@RequestMapping("/api/v1/employees")
public class EmployeeController
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
@RestController
@RequestMapping("/api/v1/auth")
public class AuthorisationController {
我感谢任何帮助
即使您正在进行本地开发,由于您是通过 https 访问您的网站,因此您应该将 Secure 标志设置为 true 以便发送 cookie。