将 JWT 与基于角色的授权一起使用
Posted
技术标签:
【中文标题】将 JWT 与基于角色的授权一起使用【英文标题】:Using JWT with role based authorization 【发布时间】:2018-11-01 06:50:43 【问题描述】:背景
我正在使用 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 时,是否有其他方法可以解决处理用户详细信息更改的问题?
【问题讨论】:
检查这个过滤器实现:github.com/szerhusenBC/jwt-spring-security-demo/blob/master/src/… 【参考方案1】:我们将 JWT 令牌与 Spring Security 和 Angular webapp 一起使用。
我认为您的Possible Solution
想法是有效的。我们以类似的方式处理这个问题。我们的身份验证流程如下所示:
由于“刷新”服务,如果用户的角色发生变化,或者如果他们被系统禁止,他们将在不迟于令牌到期时间之前自动通知新角色或被“锁定”。
这对我们来说已经好几年了。我们用户的角色不会经常更改,如果希望立即更新他们的角色,他们可以随时退出/重新登录。
其他潜在解决方案
但是,如果在您的系统中立即更新用户的角色至关重要,您可以在 Spring 中使用过滤器检查每个请求的 JWT 标头,并让它进行 JWT 验证,并添加一个新的、刷新的 JWT每个响应的令牌。
然后,您的客户端可以期望在从服务器返回的每个响应中获得一个修改后的 JWT 令牌,并将该修改后的 JWT 令牌用于每个后续请求。
这可行,但如果您有大量流量,它也会相对昂贵。
这完全取决于您的用例。就像我说的,“刷新”服务对我们来说效果很好。
【讨论】:
以上是关于将 JWT 与基于角色的授权一起使用的主要内容,如果未能解决你的问题,请参考以下文章