Spring Security:如何在不登录和注销的情况下更改用户角色

时间:2018-05-29 13:34:02

标签: java spring security authentication

Spring Security 4.2.4。 Java 8

我需要更改用户的权限而不重新登录。这是我的服务:

@Component
public class AuthoritiesUpdater {

    private final UserRoleService userRoleService;

    @Autowired
    public AuthoritiesUpdater(UserRoleService userRoleService) {
        this.userRoleService = userRoleService;
    }

    public void update(User user) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        List<UserRole> userRoles = userRoleService.findByUser(user);

        List<GrantedAuthority> actualAuthorities = userRoles.stream().map(userRole -> new 
SimpleGrantedAuthority(userRole.getRole())).collect(Collectors.toList());

        Authentication newAuth = new 
UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), actualAuthorities);

        SecurityContextHolder.getContext().setAuthentication(newAuth);
    }
}

但是有麻烦。我需要为任何用户更改角色。假设我是经理,我想更改测试用户的角色。我需要在保存配置后重新加载权限,测试用户在按下F5按钮并重新加载页面时将有新角色而无需重新登录。 但SecurityContextHolder.getContext().getAuthentication();仅为当前用户(管理员)返回身份验证对象。我需要为已更改的用户获取身份验证对象以调用new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), actualAuthorities);。 我可以为任何用户获取身份验证对象,还是可以用其他方式解决此问题?也许我可以让身份验证对象使用会话注册表?

P.S。:为用户做过期会话不是一个好选择。

2 个答案:

答案 0 :(得分:0)

解决方案比我想象的要容易一些。我有一个用户。 我可以拨打UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword(), actualAuthorities);而不是UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), actualAuthorities);。 我不需要获取身份验证对象。最终版本的服务:

@Component
public class AuthoritiesUpdater {

    private final UserRoleService userRoleService;

    @Autowired
    public AuthoritiesUpdater(UserRoleService userRoleService) {
        this.userRoleService = userRoleService;
    }

    public void update(User user) {
        List<UserRole> userRoles = userRoleService.findByUser(user);

        List<GrantedAuthority> actualAuthorities = userRoles.stream().map(userRole -> new SimpleGrantedAuthority(userRole.getRole())).collect(Collectors.toList());

        Authentication newAuth = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), actualAuthorities);

        SecurityContextHolder.getContext().setAuthentication(newAuth);
    }
}

答案 1 :(得分:0)

很好的回答,谢谢@virkom!

对于新用户,步骤如下:

  1. 创建您希望用户拥有的权限列表(包括他们以前拥有的权限)。在这种情况下(如下),我创建了一个集合,因此它们将是唯一的。

  2. 创建一个身份验证对象,该对象与您要通过其新权限进行身份验证的用户相匹配。在这种情况下,我使用了一个内存中的用户来简化示例,但是首选数据库身份验证!

  3. 使用新的身份验证信息更新安全上下文。这将具有刷新用户凭据的效果。

代码段如下所示:

Set<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("USER"));
authorities.add(new SimpleGrantedAuthority("ADMIN"));

Authentication reAuth = new UsernamePasswordAuthenticationToken("user",new 

BCryptPasswordEncoder().encode("password"),authorities);  

SecurityContextHolder.getContext().setAuthentication(reAuth);

示例代码可在github上找到:https://github.com/aoa4eva/ContextDemo