【发布时间】: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 时,是否有其他方法可以解决处理用户详细信息更改的问题?
【问题讨论】:
标签: java rest spring-security authorization jwt