如何在Angular前端持久化Spring安全认证



在对我的问题的第一个评论之后,我修改了我的Spring Security实现,并设法登录并使用Postman到达测试端点。然而,当Angular在成功登录后调用同一个端点时,调用失败,身份验证也消失了,根据日志记录,调用是匿名的。

下面是新的安全配置配置方法:

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/login", "/users").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.addFilter(getAuthenticationFilter())
.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
}

下面是getAuthenticationFilter方法:

private UsernamePasswordAuthenticationFilter getAuthenticationFilter() {
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(this.authenticationManager);
filter.setAuthenticationSuccessHandler(new HttpStatusReturningAuthenticationSuccessHandler());
filter.setAuthenticationFailureHandler(new HttpStatusReturningAuthenticationFailureHandler());
return filter;
}

和我的安全端点:

@GetMapping(path = "/test")
public ResponseEntity<ExcelUploadResponse> test() {
LOGGER.info("In test");
return new ResponseEntity<>(new ExcelUploadResponse("Test OK!"), HttpStatus.OK);
}

对于Postman,登录响应200 OK,到达测试端点并返回"test OK!"

邮差请求:

POST http://localhost:8080/api/login(以用户凭据作为主体)回应:状态200 OK (with Cookie: JSESSIONID D3BBCC0BF4134909C83FAE45C72BC5F7 localhost/annuaire Session true false)

GET http://localhost:8080/api/test回应:状态200 OK(带有"Test OK!"))

在Angular中,登录响应为200 OK,但下一个对测试端点的GET调用失败为403 Forbidden, Spring Security的调试日志如下:

2023-01-05 10:25:15.796 DEBUG 6516 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /excel/test
2023-01-05 10:25:15.796 DEBUG 6516 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2023-01-05 10:25:15.798 DEBUG 6516 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
2023-01-05 10:25:15.802 DEBUG 6516 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Failed to authorize filter invocation [GET /excel/test] with attributes [fullyAuthenticated]
2023-01-05 10:25:15.808 DEBUG 6516 --- [nio-8080-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint     : Pre-authenticated entry point called. Rejecting access
2023-01-05 10:25:15.808 DEBUG 6516 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2023-01-05 10:25:15.808 DEBUG 6516 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2023-01-05 10:25:15.808 DEBUG 6516 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2023-01-05 10:25:15.811 DEBUG 6516 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /error
2023-01-05 10:25:15.811 DEBUG 6516 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2023-01-05 10:25:15.811 DEBUG 6516 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
2023-01-05 10:25:15.811 DEBUG 6516 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Secured GET /error
2023-01-05 10:25:15.862 DEBUG 6516 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : Did not store anonymous SecurityContext
2023-01-05 10:25:15.865 DEBUG 6516 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : Did not store anonymous SecurityContext
2023-01-05 10:25:15.865 DEBUG 6516 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request

我注意到GET请求的唯一不同之处在于JSESSIONID存在于Postman请求头的Cookie key/value中,而不存在于Angular的请求头中。

我已经搜索了这个差异,并按照建议在Angular中添加了一个HttpInterceptor:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authRequest = req.clone({
withCredentials: true
});
return next.handle(authRequest);
}
}

如果我理解墙,这个HttpInterceptor与withCredentials: true应该通过拦截所有请求并将cookie添加到它们来解决cookie缺失问题。

但它不工作,我仍然有一个错误403当尝试到达测试端点后,在Angular中登录。

我终于找到了解决问题的办法。

问题是Spring Security响应与关键jsessionid饼干和一个随机值,当达到/login端点和这个饼干是返回相同的值由邮递员去获得端点时授权请求,但在角前端,尽管我添加了HttpInterceptorwhithCredentials: true,饼干是响应中过滤掉信息消息的路径说明安全cookie不匹配的请求url。

我已经添加到application.properties行:

server.servlet.session.cookie.path=/

和cookie被Angular成功发回,从而将我的请求授权给了受保护的端点。

最新更新