给定一个场景,控制器中有一些HTML内容 OR 某些方法,只允许通过“a”角色进行访问。
从上面,我们通过使用 @hasRole(“a”)
来实现但是,就我而言,角色是动态的:
例如,管理员添加新角色“b”,并且能够访问这些内容。 那怎么办呢?
我尝试过ACL,但这只是用id来保护域对象。
有一个名为hasAuthority的注释,但我无法搜索 来自互联网的任何事情。
有一个ObjectIdentityImpl,不是真的 如何实施。
答案 0 :(得分:12)
编辑:我的解决方案
经过研究,ACL更多地放在对象的安全列表中。 示例:您想要保护员工表,一些员工记录(如CEO,经理)只能由高级管理人员访问。所有员工都可以查看其他员工的记录。这就是ACL要做的事情。
但是,当我们需要保护某些方法,控制器,网址,静态内容......时,ACL不适用于此。我们需要使用 hasAuthority或hasPermission或hasRole或......
在某些网络系统中,只有少数角色,即管理员和用户。对于这种情况,hasAuthority或hasRole就足够了。你只是为想要保护的资源注释 @hasRole('admin')。
但是,在某些系统中,存在动态角色,例如:admin创建新角色“ temporary_user ”,但控制器或方法由@hasRole注释(' user < / strong>'),“ temporary_user ”无法访问。
在这种情况下,根据我的理解,几乎没有办法。
根据您想要保护的资源数量创建多个角色。例如:将“ role_getRecord ”分配给 getRecords(),将“ role_writeRecord ”分配给 writeRecord()。这是一种不改变Spring安全机制的方法,但是在数据库表上会有很多角色,而且系统会比较复杂,会有更多。
@hasPermission - 这就是我现在使用的。我创建了一个 CustomGrantedAuthority ,以便更灵活地实施。我确实有一个 CustomUserDetailsService 和 CustomSpringSecurityUser ,当用户登录时会创建 CustomSpringSecurityUser 并收集 CustomGrantedAuthority 然后返回< strong> CustomSpringSecurityUser 到 CustomUserDetailsService 。我还有一个 CustomPermission 来验证权限。
如果您认为有用,请 投票 ,如果我错了或有更好的方法,请发表评论。
这是我的代码
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;
}
}
CustomeUserDetailsService
@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)
我不知道你在资源下的意思,但我发现在春天使用它的最好方法是授予用户权限(权限)而不是角色,你仍然有角色,但他们只是在那里捆绑权限。设置完成后,您可以为视图和方法分配实际权限。我在这里找到了一个数据模型:
答案 2 :(得分:0)
如果使用Java Reflection获取每个控制器方法,然后将这些方法中的任何一个设置为角色关系以构建“动态角色”,该怎么办?这样,您可以随时向任何角色添加或删除任何操作。也许Spring Security不需要这样。