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

时间:2014-01-15 03:52:26

标签: spring spring-mvc spring-security

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

从上面,我们通过使用 @hasRole(“a”)

来实现

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

例如,管理员添加新角色“b”,并且能够访问这些内容。 那怎么办呢?

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

  2. 有一个名为hasAuthority的注释,但我无法搜索     来自互联网的任何事情。

  3. 有一个ObjectIdentityImpl,不是真的     如何实施。

3 个答案:

答案 0 :(得分:12)

编辑:我的解决方案

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

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

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

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

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

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

  4. @hasPermission - 这就是我现在使用的。我创建了一个 CustomGrantedAuthority ,以便更灵活地实施。我确实有一个 CustomUserDetailsS​​ervice CustomSpringSecurityUser ,当用户登录时会创建 CustomSpringSecurityUser 并收集 CustomGrantedAuthority 然后返回< strong> CustomSpringSecurityUser CustomUserDetailsS​​ervice 。我还有一个 CustomPermission 来验证权限。

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

  5. 这是我的代码

    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();
        }
    }
    

    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;
        }
    
    }
    

    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;
            }
        }
    }
    

    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;
        }
    
    }
    

答案 1 :(得分:1)

我不知道你在资源下的意思,但我发现在春天使用它的最好方法是授予用户权限(权限)而不是角色,你仍然有角色,但他们只是在那里捆绑权限。设置完成后,您可以为视图和方法分配实际权限。我在这里找到了一个数据模型:

http://springinpractice.com/2010/10/27/quick-tip-spring-security-role-based-authorization-and-permissions/

答案 2 :(得分:0)

如果使用Java Reflection获取每个控制器方法,然后将这些方法中的任何一个设置为角色关系以构建“动态角色”,该怎么办?这样,您可以随时向任何角色添加或删除任何操作。也许Spring Security不需要这样。