Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过基于角色的授权使用JWT 背景_Java_Rest_Spring Security_Authorization_Jwt - Fatal编程技术网

Java 通过基于角色的授权使用JWT 背景

Java 通过基于角色的授权使用JWT 背景,java,rest,spring-security,authorization,jwt,Java,Rest,Spring Security,Authorization,Jwt,我正在使用SpringSecurity开发一个web应用程序,并首次尝试使用JSONWeb令牌进行身份验证。应用程序应根据用户角色限制对某些URI的访问。它应该提供密码更改选项,并允许Admin用户更改其他用户的角色 在下面的示例中,每次向服务器发出HTTP请求时,数据库都会被CustomUserDetailsService点击,以加载用户的当前详细信息,这似乎对性能有很大影响: public class JwtAuthenticationFilter extends OncePerReques

我正在使用SpringSecurity开发一个web应用程序,并首次尝试使用JSONWeb令牌进行身份验证。应用程序应根据用户角色限制对某些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
claim)-在这段时间后,例如15分钟,我们点击数据库检查用户的详细信息。如果角色已更改,我们将在有效负载中使用新角色生成新令牌。如果密码已更改,我们要求用户在生成新令牌之前重新验证

此解决方案的一个明显缺点是,用户访问权限的任何更改都会在过期后生效

问题:
在使用JWTs时,有没有其他方法来解决处理用户详细信息更改的问题?

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

我认为你的
可能的解决方案
想法是有效的。我们以类似的方式处理这个问题。我们的身份验证流程如下所示:

  • 用户在URL处登录,响应头包含JWT令牌
  • JWT令牌有一个短超时(分钟)
  • webapp以更短的时间间隔ping“刷新令牌”服务,该服务检测令牌是否有效。如果是这样,服务器将重新发布一个新的令牌,其中包括用户的任何更新角色,然后由webapp存储,以便在将来对后端的请求中包含该令牌
由于“刷新”服务,如果用户的角色发生更改,或者如果他们被禁止进入系统,他们将自动通知新角色,或者在令牌到期时间之前被“锁定”

多年来,这对我们很有效。我们用户的角色不会经常更改,如果需要立即更新他们的角色,他们可以随时注销/重新登录

其他潜在解决方案

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

然后,您的客户机可以期望在从服务器返回的每个响应上获得一个修改后的JWT令牌,并在每个后续请求中使用该修改后的JWT令牌

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


这完全取决于您的用例。正如我所说,“刷新”服务对我们很有效。

检查此筛选器实现: