Spring安全性,如何根据动态角色限制用户访问某些资源?

Stu*_*rog 6 spring spring-mvc spring-security

给定一个场景,控制器中有HTML内容某些方法,只允许通过"a"角色进行访问.

从上面,我们通过使用@hasRole("a")实现

但是,就我而言,角色是动态的:

例如,admin添加一个新角色"b",并且能够访问这些内容.那怎么办呢?

  1. 我尝试过ACL,但这只是用id来保护域对象.

  2. 有一个名为hasAuthority的注释,但我无法从互联网搜索任何东西.

  3. 有一个ObjectIdentityImpl,实际上并不是如何实现的.

Stu*_*rog 13

编辑:我的解决方案

  1. 经过研究,ACL更多地放在对象的安全列表中.示例:您想要保护员工表,一些员工记录(如CEO,经理)只能由高级管理人员访问.所有员工都可以查看其他员工的记录.这就是ACL要做的事情.

    但是,当我们需要保护一些方法,控制器,URL,静态内容...... ACL不适用于此.我们需要使用hasAuthority或hasPermission或hasRole或......

  2. 在某些Web系统中,只有很少的角色,管理员和用户.对于这种情况,hasAuthority或hasRole就足够了.你只是为你想要保护的资源注释@hasRole('admin').

    但是,在某些系统中,存在动态角色,例如:admin创建新角色" temporary_user ",但控制器或方法由@hasRole(' user ')注释," temporary_user " 无法访问.

    在这种情况下,根据我的理解,几乎没有办法.

  3. 根据您想要保护的资源数量创建许多角色.例如:将' role_getRecord ' 赋值给getRecords(),将' role_writeRecord ' 赋值给writeRecord().这是一种不改变spring安全机制的方法,但是在你的数据库表上会有很多角色,而且系统会比较复杂,会有更多.

  4. @hasPermission - 这就是我现在使用的.我创建一个CustomGrantedAuthority,以便更灵活地实现.我有一个CustomUserDetailsS​​erviceCustomSpringSecurityUser,当用户登录时将使用CustomGrantedAuthority集合创建CustomSpringSecurityUser,然后将CustomSpringSecurityUser返回给CustomUserDetailsS​​ervice.我也有一个CustomPermission来验证权限.

    如果您认为有用,请投票UP,如果我错了或者有更好的方法,请发表评论.

这是我的代码

CustomSpringSecurityUser

public class CustomSpringSecurityUser implements UserDetails, CredentialsContainer {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    private String password;
    private final String username;
    private final Set<GrantedAuthority> authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;

    public CustomSpringSecurityUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        this(username, password, true, true, true, true, authorities);
    }
    public CustomSpringSecurityUser(String username, String password, boolean enabled, boolean accountNonExpired,
            boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
      //  this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
        this.authorities = new HashSet<GrantedAuthority>(authorities);
    }
    public Collection<GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }

    public boolean isAccountNonLocked() {
        return accountNonLocked;
    }

    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }

    public void eraseCredentials() {
        password = null;
    }

    private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        SortedSet<GrantedAuthority> sortedAuthorities =
            new TreeSet<GrantedAuthority>(new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }

    private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
        private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

        public int compare(GrantedAuthority g1, GrantedAuthority g2) {
            if (g2.getAuthority() == null) {
                return -1;
            }

            if (g1.getAuthority() == null) {
                return 1;
            }

            return g1.getAuthority().compareTo(g2.getAuthority());
        }
    }

    @Override
    public boolean equals(Object rhs) {
        if (rhs instanceof CustomSpringSecurityUser) {
            return username.equals(((CustomSpringSecurityUser) rhs).username);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return username.hashCode();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(super.toString()).append(": ");
        sb.append("Username: ").append(this.username).append("; ");
        sb.append("Password: [PROTECTED]; ");
        sb.append("Enabled: ").append(this.enabled).append("; ");
        sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
        sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
        sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");

        if (!authorities.isEmpty()) {
            sb.append("Granted Authorities: ");

            boolean first = true;
            for (GrantedAuthority auth : authorities) {
                if (!first) {
                    sb.append(",");
                }
                first = false;

                sb.append(auth);
            }
        } else {
            sb.append("Not granted any authorities");
        }

        return sb.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

CustomGrantedAuthority

public class CustomGrantedAuthority implements GrantedAuthority{
    private String role;
    private String permission,action;

    public String getPermission() {
        return permission;
    }

    public void setPermission(String permission) {
        this.permission = permission;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    @Override
    public String getAuthority() {
        return role;
    }

}
Run Code Online (Sandbox Code Playgroud)

CustomeUserDetailsS​​ervice

@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
        private OcUserService userService;
        private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            sg.com.xx.xx.table.OcUser u = userService.findByLoginname(username);

                        String pass = sg.com.xx.xx.table.OcUser.byteToHex(u.getPassword());
            Collection<? extends GrantedAuthority> permissionList = userService.getPermissionByUserId(u.getId());

            boolean enabled = true;
            boolean accountNonExpired = true;
            boolean credentialsNonExpired = true;
            boolean accountNonLocked = true;
                        CustomSpringSecurityUser user = new CustomSpringSecurityUser(u.getLoginname(), 
                    pass,
                    enabled,
                    accountNonExpired,
                    credentialsNonExpired,
                    accountNonLocked,
                    permissionList);

            return user;

        } catch (Exception e) {
            logger.error("==============================================");
                        logger.error(e.toString());
                        return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

CustomPermission

public class CustomPermission implements PermissionEvaluator {

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        Collection<? extends GrantedAuthority> x = authentication.getAuthorities();

        for(Object o : x)
        {
            CustomGrantedAuthority y = (CustomGrantedAuthority) o ;
            if(y.getPermission().equals(targetDomainObject) )
                if( y.getAction().equals(permission) )
                    return true;
        }
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        int a = 5;
        return true;
    }

}
Run Code Online (Sandbox Code Playgroud)