我正在使用Spring Security开发一个Web应用程序,并尝试首次使用JSON Web令牌进行身份验证。该应用应根据用户角色限制对某些URI的访问。它应该提供密码更改选项,并使Admin
用户能够更改其他用户的角色。
在我遵循的教程中,在对服务器的每个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时处理用户详细信息更改的问题吗?
我们将JWT令牌与Spring Security和Angular webapp一起使用。
我认为你的Possible Solution
想法是正确的。我们以类似的方式处理。我们的身份验证流程如下所示:
由于提供了“刷新”服务,如果用户的角色发生更改或被系统禁止,他们将自动获悉新角色,或者不迟于令牌到期时间被“锁定”。
多年来,这对我们来说一直很好。我们用户的角色不会经常更改,并且如果需要立即更新其角色,则可以随时注销/重新登录。
其他潜在解决方案
但是,如果最重要的是要立即在系统中更新用户的角色,则可以让Spring的Filter在每个请求中检查JWT标头,并执行JWT验证,并在每个请求上添加新的,刷新的JWT令牌。响应。
然后,您的客户端可以期望从服务器返回的每个响应上获得修订的JWT令牌,并将该修订的JWT令牌用于每个后续请求。
这可以工作,但是如果您的流量很大,则费用也相对较高。
这完全取决于您的用例。就像我说的那样,“刷新”服务对我们来说效果很好。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句