JWT 身份验证,无需获取每个请求的用户详细信息

Posted

技术标签:

【中文标题】JWT 身份验证,无需获取每个请求的用户详细信息【英文标题】:JWT authentication without fetching user details on each request 【发布时间】:2018-11-07 09:35:37 【问题描述】:

我正在 Spring Security 中实现 JWT 身份验证。 我有预定义的角色,例如。普通用户、管理员等

我有以下令牌负载:


  "sub": "nick",
  "iat": "<some_date>",
  "exp": "<some_date+1h>",
  "scopes": [
    "ROLE_USER",
    "ROLE_ADMIN"
  ]

到目前为止,我看到的大多数实现都基于 id/username/email 从数据库中检索用户详细信息,然后使用这些数据来创建身份验证(例如,通过身份验证 UsernamePasswordAuthenticationToken)。 对我来说,这实际上是一种更可取的方式,因为我总是拥有最新的特权和限制(例如,用户是否被禁止)并且与收益相比,时间开销并没有那么大。

我只是好奇如何仅基于传入请求中包含的角色(在其授权标头令牌中)使用 Spring Security 实现授权。我希望能够在请求被适当路由后访问控制器中的用户标识符。仅基于检查过期时间和角色有效性的令牌验证是否足够?

【问题讨论】:

你能发布你的配置类中的内容吗? 【参考方案1】:

由于有关用户角色的信息是您的令牌的一部分(在scopesclaim 中),因此可以仅基于令牌创建身份验证对象,而无需进一步访问数据库。

在以下示例中,createAuthentication() 方法将令牌转换为 Spring Security Authentication 对象。

public class JWTFilter extends GenericFilterBean 

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException 

        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String jwt = // resolveToken(httpServletRequest);

        this.createAuthentication(jwt).ifPresent(authentication -> 
            SecurityContextHolder.getContext().setAuthentication(authentication);
        );

        filterChain.doFilter(servletRequest, servletResponse);
    


    public Optional<Authentication> createAuthentication(String token) 

        Jws<Claims> jwsClaims = validateToken(token);
        if (jwsClaims == null) 
            return Optional.empty();
        

        Claims claims = jwsClaims.getBody();

        String scopesString = claims.get("scopes").toString();
        String[] authStrings = scopesString.split(",");

        Collection<? extends GrantedAuthority> authorities =
            Arrays.stream(authStrings)
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());

        String subject = claims.getSubject();
        org.springframework.security.core.userdetails.User principal = new User(subject, "", authorities);

        return Optional.of(new UsernamePasswordAuthenticationToken(principal, token, authorities));
    

    private Jws<Claims> validateToken(String authToken) 
        try 
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
            return claims;
         catch ...
    


【讨论】:

以上是关于JWT 身份验证,无需获取每个请求的用户详细信息的主要内容,如果未能解决你的问题,请参考以下文章

JWT 令牌作为 API 中用户详细信息的来源?

身份验证后请求其他服务时如何从 JWT 令牌获取用户名?

实现 JWT 身份验证 Azure Function 3.x - 使用 JWT 令牌获取当前用户的声明

使用JWT身份验证缓存API请求

如何使用 JWT 身份验证获取登录用户信息?

laravel 中 jwt 身份验证中授权标头的作用