使用JWT进行基于角色的授权

3

背景

我正在开发一个使用Spring Security的Web应用程序,并尝试首次使用JSON Web Tokens进行认证。该应用程序应根据用户角色限制对某些URI的访问。它应提供更改密码选项并允许管理员用户更改其他用户的角色。

在我遵循的教程中,每个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时,是否有其他处理用户详细信息更改问题的方法?


请检查此过滤器实现: https://github.com/szerhusenBC/jwt-spring-security-demo/blob/master/src/main/java/org/zerhusen/security/JwtAuthorizationTokenFilter.java - KeyMaker00
1个回答

2
我们在使用Spring Security和Angular Web应用程序中使用JWT令牌。我认为你的“可能的解决方案”想法是有效的。我们以类似的方式处理它。我们的认证流程如下:
- 用户在URL上登录,响应头包含JWT令牌。 - JWT令牌具有较短的超时时间(几分钟)。 - Web应用程序以更短的间隔向“刷新令牌”服务发送请求,该服务检测令牌是否有效。如果有效,则服务器重新发出新令牌,其中包括用户的任何更新角色,并由Web应用程序存储以供将来请求后端时使用。
由于“刷新”服务,如果用户的角色发生变化或者他们被禁止使用系统,则最迟在令牌过期时间之前,他们将自动注意到新角色或被“锁定”。
这对我们来说已经运作良好多年了。我们的用户角色不经常更改,如果需要立即更新他们的角色,他们可以随时退出/重新登录。
但是,如果在您的系统中立即更新用户角色至关重要,您可以在Spring中添加一个过滤器,在每个请求中检查JWT标头,并进行JWT验证,并在每个响应上添加一个新的、刷新的JWT令牌。
然后,您的客户端可以期望从服务器每次收到修订后的JWT令牌,并将其用于每个后续请求。这将起作用,但如果您有大量流量,它也会相对昂贵。
这完全取决于您的用例。就像我说的那样,“刷新”服务已经对我们运作良好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接