【问题标题】:How to perform Auth0 JWT token user Role-based authorization如何执行 Auth0 JWT 令牌用户基于角色的授权
【发布时间】:2020-09-13 02:10:16
【问题描述】:

我正在编写 Spring Boot REST API,并且正在使用 JWT 令牌。现在,我正在尝试创建基于角色的授权。

这是我正在使用的教程/实现。

https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/

我用额外的 Role 实体扩展了这个实现,并将 @ManyToMany 映射添加到 ApplicationUser 实体。

现在,据我了解,应该将用户角色添加到令牌(在其创建期间)。 所以,这是一个现有的代码:

@Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException, ServletException {


        String token = JWT.create()
                .withSubject(((User) auth.getPrincipal()).getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .sign(HMAC512(SECRET.getBytes()));
        res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
    }

我想应该在那里添加用户角色。有一个功能:

withArrayClaim(String Name, String[] items)

这是我的第一个问题:我不确定如何正确添加它。

那么,就是这个片段,据我了解是验证token的地方:

private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(HEADER_STRING);
        if (token != null) {
            // parse the token.
            String user = JWT.require(Algorithm.HMAC512(SECRET.getBytes()))
                    .build()
                    .verify(token.replace(TOKEN_PREFIX, ""))
                    .getSubject();

            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }

困扰我的是片段:

return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());

我不明白为什么会有 null(Inteliij 将其突出显示为“凭据”)和这个新的 ArrayList。有没有地方,我应该从令牌中获取角色并添加它们?

我知道,这是一个范围广泛的问题,但我找不到其他解决方案。 或者也许有一种更简单的方法来创建简单的 JWT 令牌认证/授权(基于角色)。

期待您的回答!

编辑:

或者也许有更简单的解决方案i - 不将用户角色保留在密钥中 - 而是仅将它们添加到 null 和 new ArrayList 所在的“第二”部分?

【问题讨论】:

    标签: spring-boot spring-security jwt auth0 jwt-auth


    【解决方案1】:

    只需根据用户角色创建授予的权限并使用它对用户进行身份验证。然后经过身份验证的用户主体将包含角色。 简单例子:

    UserEntity userEntity = userRepository.findUserByEmail(user); // this depends of course on your implementation
    if (userEntity == null) return null;
    List<RoleEntity> roles = userEntity.getRoles();
    Collection<GrantedAuthority> authorities = new HashSet<>();
    roles.forEach((role) -> {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
    });
    return new UsernamePasswordAuthenticationToken(user, null, authorities);
    

    更好的是,您可以创建一个从 Spring Security 实现 UserDetails 的 UserPrincipal。

    public class UserPrincipal implements UserDetails {
    
    private static final long serialVersionUID = 1L;
    private final UserEntity userEntity;
    
    public UserPrincipal(UserEntity userEntity){
        this.userEntity = userEntity;
    }
    
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new HashSet<>();
    
        // Get user Roles
        Collection<RoleEntity> roles = userEntity.getRoles();
    
        if(roles == null) return authorities;
    
        roles.forEach((role) -> {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        });
    
        return authorities;
    }
    
    @Override
    public String getPassword() {
        return this.userEntity.getEncryptedPassword();
    }
    
    @Override
    public String getUsername() {
        return this.userEntity.getEmail();
    }
    
    @Override
    public boolean isAccountNonExpired() {
        return false;
    }
    
    @Override
    public boolean isAccountNonLocked() {
        return false;
    }
    
    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }
    
    @Override
    public boolean isEnabled() {
        return false;
    }
    }
    

    并使用它:

    UserEntity userEntity = userRepository.findUserByEmail(user);
    if (userEntity == null) return null;
    
    UserPrincipal userPrincipal = new UserPrincipal(userEntity);
      return new UsernamePasswordAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities());
    

    【讨论】:

    • 嗨,也许你知道,问题可能出在哪里:尝试通过用户名获取用户总是抛出 NullPointerException(在 getAuthentication 函数内部(我的帖子中的第二个函数))。通过用户名获取用户正在工作,因为当我尝试通过端点访问它时,用户被正确返回。
    • @Nickname11 我想我不明白这两种情况之间的区别。在您的 getAuthentication 函数中,用户是什么?是从 JWT 令牌中获取的用户名吗?然后当您执行 findByUsername 时会引发空指针异常?也许你可以发布一个新问题
    • 是的,和你写的完全一样。我确定 findByUsername 函数正在工作 -> 因为它返回正确的值,但只有当我在不同的地方使用它时(我在端点测试它)。
    • 也许您的 userRepository 没有被注入到您的课程中?然后它总是空的。我认为这是一个很好的解释。
    • @Nickname11 我回答了。如果您有任何问题,请告诉我
    猜你喜欢
    • 2017-12-14
    • 2017-06-24
    • 2018-04-17
    • 2016-07-20
    • 2018-03-01
    • 2019-12-11
    • 2023-03-22
    • 2018-12-25
    • 2020-07-09
    相关资源
    最近更新 更多