You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 02:41:03