Angular对接Spring Security登录前端报401问题求助
问题
Angular前端对接Spring Boot后端实现用户登录验证,Postman调用登录接口正常,但前端发送相同请求数据时返回401未授权。后端日志显示前端请求时userName为null,Postman请求则能正确获取。已确认两者Content-Type均为application/x-www-form-urlencoded,请求格式一致。
前端登录服务代码
export class LoginService { loginUrl = "http://localhost:8080/login"; private token!: string; constructor(private http:HttpClient) { } singIn(user: LoginForm){ let body = new HttpParams().set("userName", user.userName).set("password", user.password); let headers = new HttpHeaders({'Content-Type': 'Application/x-www-form-urlencoded'}); let options = {headers: headers}; this.http.post(this.loginUrl, body.toString(), options).subscribe((response: any) => { console.log(response); }) } }
后端AuthenticationFilter代码
public class AutheFilter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager; public AutheFilter(AuthenticationManager authenticationManager){ this.authenticationManager = authenticationManager; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { String userName = request.getParameter("userName"); System.out.println(userName); String password = request.getParameter("password"); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName, password); return authenticationManager.authenticate(authenticationToken); } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,Authentication authentication) throws IOException, ServletException { User user = (User)authentication.getPrincipal(); Algorithm algorithm = Algorithm.HMAC256("mattAl".getBytes()); String access_token = JWT.create() .withSubject(user.getUsername()) .withExpiresAt(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) .withIssuer(request.getRequestURL().toString()) .withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())) .sign(algorithm); response.setHeader("access_token", access_token); } }
原因分析
核心问题是:Angular中手动将HttpParams转为字符串传递给post方法,导致后端无法正确解析表单参数。HttpClient本身会自动处理HttpParams的编码与格式转换,手动调用toString()会破坏参数的正确编码格式,使得后端request.getParameter()无法读取到userName和password的值,进而触发身份验证失败返回401。另外前端设置的Content-Type首字母大写虽不影响HTTP解析,但存在不规范问题。
解决方案
1. 修正前端请求体传递方式
直接将HttpParams对象作为请求体传递,无需转为字符串,同时规范Content-Type的写法:
singIn(user: LoginForm){ let body = new HttpParams() .set("userName", user.userName) .set("password", user.password); // 规范Content-Type为小写标准写法 let headers = new HttpHeaders({'Content-Type': 'application/x-www-form-urlencoded'}); let options = {headers: headers}; // 直接传递HttpParams对象,由HttpClient自动处理编码 this.http.post(this.loginUrl, body, options).subscribe((response: any) => { console.log(response); }) }
2. 检查并配置后端跨域(可选)
如果前端和后端存在跨域问题,也可能间接导致请求异常,可在Spring Boot添加CORS配置:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:4200") // 替换为你的Angular前端地址 .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true); } }
内容的提问来源于stack exchange,提问作者MathP4nk
相关产品推荐
相关产品推荐

