【问题标题】:how to get claims value from JWT token authentication如何从 JWT 令牌身份验证中获取声明值
【发布时间】:2019-06-17 18:49:17
【问题描述】:

我已在令牌提供程序的 JWT 令牌中设置声明。现在我想在 API 被命中时通过身份验证获取声明值。

我已经检查了委托人、详细信息、凭据、权限,但我没有收到任何声明。

Claims claims = Jwts.claims().setSubject(authentication.getName());
    claims.put(AUTHORITIES_KEY, authorities);
    claims.put("userId", userRepo.findUserIdByUsername(authentication.getName()));

   return Jwts.builder()
            .setSubject(authentication.getName())
            .setClaims(claims)
            //.claim(AUTHORITIES_KEY, authorities)
            .signWith(SignatureAlgorithm.HS512, SIGNING_KEY)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_VALIDITY_SECONDS*1000))
            .compact();

我想通过身份验证或任何其他方式从令牌中获取“userId”声明。

【问题讨论】:

    标签: java spring spring-boot spring-security jwt


    【解决方案1】:

    应该有帮助。

    您应该能够在您的控制器中检索这样的声明

    var identity = HttpContext.User.Identity as ClaimsIdentity;
    if (identity != null)
    {
        IEnumerable<Claim> claims = identity.Claims; 
        // or
        identity.FindFirst("ClaimName").Value;
    
    }
    

    如果您愿意,您可以为 IPrincipal 接口编写扩展方法并使用上面的代码检索声明,然后使用(例如)检索它们

    HttpContext.User.Identity.MethodName();
    

    为了答案的完整性。为了解码 JWT 令牌,让我们编写一个方法来验证令牌并提取信息。

    public static ClaimsPrincipal ValidateToken(string jwtToken)
        {
            IdentityModelEventSource.ShowPII = true;
    
            SecurityToken validatedToken;
            TokenValidationParameters validationParameters = new TokenValidationParameters();
    
            validationParameters.ValidateLifetime = true;
    
            validationParameters.ValidAudience = _audience.ToLower();
            validationParameters.ValidIssuer = _issuer.ToLower();
            validationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Secret));
    
            ClaimsPrincipal principal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);
    
    
            return principal;
        }
    

    现在我们可以使用以下方法验证和提取声明:

    ValidateToken(tokenString)?.FindFirst("ClaimName")?.Value

    请注意,如果验证失败,ValidateToken 方法将返回 null 值。

    【讨论】:

    • 您提供的答案是否有任何参考资料。我无法获得 HttpContext.User.Identity
    • @sameernainawat 这似乎不是 Java,而是 Kotlin 代码。
    • @sameernainawat as 中的 HttpContext.User.Identity as ClaimsIdentity 不是 Java 中的有效关键字。如果您使用的不是纯 Java,请在您的问题中说明。
    【解决方案2】:

    这就是我从 Token 读取声明的方式

    private Claims getAllClaimsFromToken(String token) {
            Claims claims;
            try {
                claims = Jwts.parser()
                        .setSigningKey(SECRET)
                        .parseClaimsJws(token)
                        .getBody();
            } catch (Exception e) {
                LOGGER.error("Could not get all claims Token from passed token");
                claims = null;
            }
            return claims;
        }
    

    我正在为 JWT 使用它

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>
    

    More detail here

    编辑 1:

    添加过滤器以从请求和验证中获取令牌

    import java.io.IOException;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    public class TokenAuthenticationFilter extends OncePerRequestFilter {
    
        protected final Log logger = LogFactory.getLog(getClass());
    
        private TokenHelper tokenHelper;
    
        private UserDetailsService userDetailsService;
    
        public TokenAuthenticationFilter(TokenHelper tokenHelper, UserDetailsService userDetailsService) {
            this.tokenHelper = tokenHelper;
            this.userDetailsService = userDetailsService;
        }
    
    
        @Override
        public void doFilterInternal(
                HttpServletRequest request,
                HttpServletResponse response,
                FilterChain chain
        ) throws IOException, ServletException {
    
            String username;
            String authToken = tokenHelper.getToken(request);
    
            logger.info("AuthToken: "+authToken);
    
            if (authToken != null) {
                // get username from token
                username = tokenHelper.getUsernameFromToken(authToken);
                logger.info("UserName: "+username);
                if (username != null) {
                    // get user
                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                    if (tokenHelper.validateToken(authToken, userDetails)) {
                        // create authentication
                        TokenBasedAuthentication authentication = new TokenBasedAuthentication(userDetails);
                        authentication.setToken(authToken);
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }else{
                    logger.error("Something is wrong with Token.");
                }
            }
            chain.doFilter(request, response);
        }
    
    
    
    }
    

    【讨论】:

    • API 被命中时如何获取令牌...?
    • 如果您看到我添加的链接。有 TokenAuthenticationFilter 类,当 API 被命中时我会得到 Token。你可以做类似的事情
    • 我已经看过你的代码,但我没有得到我的问题的答案,即当我们点击 API 时,在控制器端我们只能获得主体、详细信息、凭据、权限和代码,我们正在生成令牌,所以我发现它与我的问题无关。
    【解决方案3】:

    建议参考下面给出的博客。它解释了 JWT 令牌在 Spring Boot 中的工作原理

    https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/

    【讨论】:

      【解决方案4】:

      使用 Spring Security 5,您可以在控制器方法中使用 @AuthenticationPrincipal org.springframework.security.oauth2.jwt.Jwt token 作为参数。然后拨打token.getClaims()

      【讨论】:

      • 有效!但是在集成测试中,你如何模拟令牌?
      猜你喜欢
      • 2019-01-04
      • 2020-06-12
      • 2019-01-22
      • 1970-01-01
      • 1970-01-01
      • 2020-11-29
      • 2020-09-06
      • 2017-10-22
      • 1970-01-01
      相关资源
      最近更新 更多