将JWT与基于角色的授权

时间:2018-05-22 13:17:50

标签: java rest spring-security authorization jwt

背景

我正在使用Spring Security开发Web应用程序,并且我第一次尝试使用JSON Web Tokens进行身份验证。应用程序应根据用户角色限制对某些URI的访问。它应该提供密码更改选项,并允许Admin用户更改其他用户'作用。

在随后的tutorial中,在对服务器的每个HTTP请求中,数据库被CustomUserDetailsService命中,以加载用户的当前详细信息,这些信息似乎很重要:

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    //...

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 
                                    FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = getJwtFromRequest(request);

            if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
                Long userId = tokenProvider.getUserIdFromJWT(jwt);

                UserDetails userDetails = customUserDetailsService.loadUserById(userId);
                UsernamePasswordAuthenticationToken authentication = 
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception ex) {
            logger.error("Could not set user authentication in security context", ex);
        }

        filterChain.doFilter(request, response);
    }

    //...

}

本教程的作者提出了另一种选择:

  

请注意,您还可以在JWT声明中对用户的用户名和角色进行编码,并通过解析来自JWT的声明来创建UserDetails对象。

但是,这会导致难以改变用户的角色,因为我们无法丢弃已发行的令牌,而无法跟踪它们。

可能的解决方案

我研究了JWT的主题并提出了以下解决方案:

让我们在JWT声明中存储用户名和角色,并设置一个短令牌到期时间(使用exp声明) - 在此期限之后,例如15分钟后,我们点击数据库查看用户的详细信息。如果角色已更改,我们将在有效负载中生成具有新角色的新令牌。如果密码已更改,我们要求用户在生成新令牌之前重新进行身份验证。

此解决方案的一个明显缺点是用户访问权限的任何更改在到期时间之后都有效。

问题

在使用JWT时,还有其他方法可以解决处理用户详细信息更改的问题吗?

1 个答案:

答案 0 :(得分:1)

我们使用带有Spring Security和Angular webapp的JWT令牌。

我认为您的Possible Solution想法是有效的。我们以类似的方式处理这个问题。我们的身份验证流程如下:

  • 用户在URL处登录,响应标头包含JWT令牌
  • JWT令牌有超时(分钟)
  • webapp以较短的间隔执行“刷新令牌”服务,该服务检测令牌是否有效。如果是,则服务器重新发出新令牌,包括用户的任何更新角色,然后由webapp存储,以包含在将来对后端的请求中。

由于“刷新”服务,如果用户的角色发生变化,或者他们被禁止进入系统,他们将自动注意到新角色,或者在令牌到期时间之前被“锁定”。 / p>

这对我们来说已经有好几年了。我们的用户角色不会经常更改,如果希望立即更新其角色,他们可以随时注销/重新登录。

其他潜在解决方案

但是,如果在系统中立即更新用户的角色至关重要,那么可以在Spring中检查每个请求上的JWT标头,并让它进行JWT验证,并添加一个新的,刷新的JWT每个回复都有令牌。

然后,您的客户端可以期望从服务器返回每个响应的修订JWT令牌,并为每个后续请求使用修订后的JWT令牌。

这可行,但如果您有大量流量,它也会相对昂贵。

这完全取决于您的使用案例。就像我说的那样,“刷新”服务对我们来说效果很好。