首页 文章

使用JWT和基于角色的授权

提问于
浏览
3

背景

我正在使用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 回答

  • 1

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

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

    • 用户在URL处登录,响应头包含JWT令牌

    • JWT令牌短暂超时(分钟)

    • webapp以较短的间隔执行'refresh token'服务,检测令牌是否有效 . 如果是,则服务器重新发布包括用户的任何更新角色的新令牌,然后由webapp存储该令牌以包括在将来对后端的请求中 .

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

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

    Additional potential solution

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

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

    这可行,但如果你有很多流量,它也会相对昂贵 .

    这一切都取决于您的用例 . 就像我说的那样,'刷新'服务对我们来说效果很好 .

相关问题