【问题标题】:Angular fails to receive the JWT token from Spring BootAngular 无法从 Spring Boot 接收 JWT 令牌
【发布时间】:2019-12-08 02:13:07
【问题描述】:

我在控制台中收到此错误:

null
dan
TypeError: Cannot read property 'token' of null
at MapSubscriber.project (basic-authentication.service.ts:29)
at MapSubscriber._next (map.js:29)
at MapSubscriber.next (Subscriber.js:49)
at MapSubscriber._next (map.js:35)
at MapSubscriber.next (Subscriber.js:49)
at FilterSubscriber._next (filter.js:33)
at FilterSubscriber.next (Subscriber.js:49)
at MergeMapSubscriber.notifyNext (mergeMap.js:69)
at InnerSubscriber._next (InnerSubscriber.js:11)
at InnerSubscriber.next (Subscriber.js:49)

我正在尝试从 Angular 7 前端对用户进行身份验证。当我使用 Postman 进行测试时,它适用于所有请求(即使使用 JWT 令牌)。

我在 intelliJ 上启用调试器的情况下再次运行登录操作,并且 JWT 已正确创建并发送,但它在 Angular 前端应用程序上似乎为空。

***请注意,我可能在 Spring 中处于中间状态,但在 Angular 中确实是新手

这是我的 Angular 代码被调用:

    executeJWTAuthenticationService(username, password) {
    return this.http.post<any>(
      `${API_URL}/login`, {
        username,
        password
      }).pipe(
        map(
          data => {
            console.log(data);
            console.log(username);
            sessionStorage.setItem(AUTHENTICATED_USER, username);
            sessionStorage.setItem(TOKEN, `Bearer ${data.token}`);
            return data;
          }
        )
      );
  }

这是我的 JwtAuthenticationFilter

    public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    /* Trigger when we issue POST request to /login
    We also need to pass in {"username":"dan", "password":"dan123"} in the request body
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        // Grab credentials and map them to login viewmodel
        LoginViewModel credentials = null;
        try {
            credentials = new ObjectMapper().readValue(request.getInputStream(), LoginViewModel.class);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Create login token
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                credentials.getUsername(),
                credentials.getPassword(),
                new ArrayList<>());

        // Authenticate user
        Authentication auth = authenticationManager.authenticate(authenticationToken);

        return auth;
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        // Grab principal
        UserPrincipal principal = (UserPrincipal) authResult.getPrincipal();

        // Create JWT Token
        String token = JWT.create()
                .withSubject(principal.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() + JwtProperties.EXPIRATION_TIME))
                .sign(HMAC512(JwtProperties.SECRET.getBytes()));

        // Add token in response
        response.addHeader(JwtProperties.HEADER_STRING, JwtProperties.TOKEN_PREFIX + token);
    }
}

【问题讨论】:

  • 也许可以试试{username: username, password: password} 作为对象?
  • @Fussel 我需要像“用户名”:“用户名”这样的逗号吗? (再次,Angular 新手)
  • 好吧,你可能需要return this.http.post( `${API_URL}/login`, JSON.stringify({username: username,password: password}), [...] 之类的东西,假设你的 API 使用 JSON(在这种情况下你还应该设置 content-type 标头),而在 JS/TS 中你不需要“ username" 用逗号,因为第一个是对象的属性,第二个是你的参数变量。
  • 看起来您的 API 根本没有向前端发送任何内容。现在我根本不知道 Spring:Spring 是否可能因为浏览器的飞行前 OPTIONS 请求而做出奇怪的反应?你在处理 CORS 吗?
  • 您的背部似乎将 jwt 令牌作为标题返回,但您尝试以角度从正文中读取它。尝试在春季将令牌添加到您的正文响应中或以角度解析标头

标签: angular spring-security jwt


【解决方案1】:

只需尝试在您的角度 http 调用中观察响应。 然后您将能够从响应标头中读取 JWT 令牌。

executeJWTAuthenticationService(username, password) {
    return this.http.post<any>(
        `${API_URL}/login`, {
            username,
            password
        }, {observe: 'response'}).pipe(
        map(
            data => {
                const token = data.headers.get("Authorization");
                console.log(data);
                console.log(username);
                sessionStorage.setItem(AUTHENTICATED_USER, username);
                sessionStorage.setItem(TOKEN, `Bearer ${token}`);
                return data;
            }
        )
    );
}

【讨论】:

  • 如果您想了解更多关于如何将 spring security 与 angular 连接以通过 JWT 进行身份验证的信息,我建议您查看 JHipster 实现。你会学到很多东西:github.com/jhipster/jhipster-sample-app
  • 谢谢!我最终解决了这个问题,但忘记了这篇文章。我开始使用 data.headersconsole.log 并发现我应该使用 data.headers.get('authorization') 。这是对我有用的代码:
  • executeJWTAuthenticationService(username, password) { return this.http.post&lt;any&gt;( ${API_URL}/login, { username, password }, { observe: 'response' }).pipe( map( data =&gt; { sessionStorage.setItem(AUTHENTICATED_USER, username); sessionStorage.setItem(TOKEN, data.headers.get('authorization')); return data; } ) ); } ,抱歉我不知道如何编辑评论中的代码
猜你喜欢
  • 2017-10-03
  • 2021-01-19
  • 2021-10-13
  • 2019-09-04
  • 2019-07-21
  • 2021-07-03
  • 2020-10-06
  • 2020-02-12
  • 2018-10-29
相关资源
最近更新 更多