我在 Spring Security 中授权嵌套帐户时遇到困难。我是 Spring Security 的新手。我花了大约一周的时间才找到一个可行的解决方案,但它是一个丑陋的解决方案,我很想重构它......
我正在使用 Spring 4.2.4 和 Spring Security 4.0.3。
我的用户帐户如下所示:
Office用户A
Office用户B
现场用户C
--> 字段子用户 a
--> 字段子用户 b
现场用户D
--> 字段子用户 c
因此,办公室用户只有一个帐户,但现场用户始终至少有一个子帐户,并且可能有两个或更多子帐户。每个子账户可以有不同的权限。就像一个子账户只能查看,另一个子账户可以查看和创建。
用户将使用帐户(A、B、C 或 D)登录。如果 A 或 B 登录,则没有问题。但是,如果用户 C 登录,他们需要选择(a 或 b),我们需要他们的选择信息。如果用户 D 登录,我们需要用户 (c) 的信息。我正在使用 Spring Security 并努力获取上面的用户 a/b/c 的信息。我找到了一个解决方案,但并不理想,我想知道更合适的方法。
我的解决方案:
在 UserDetails 的 @AuthenticationPrincipal 实现中,添加以下代码:
private Collection<GrantedAuthority> authorities;
private String uniqueId1;
private String uniqueId2;
public void setAuthorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
}
public Collection<GrantedAuthority> getAuthorities() {
if (this.authorities != null) {
return this.authorities; //CHILD
}
return super.getAuthorities(); // (SUPER)
}
public void setUniqueId1(String uniqueId1) {
this.uniqueId1 = uniqueId1;
}
public String getUniqueId1() {
if (this.uniqueId1!= null) {
return this.uniqueId1; //CHILD
}
return super.getUniqueId1(); // (SUPER)
}
public void setUniqueId2(String uniqueId2) {
this.uniqueId2 = uniqueId2;
}
public String getUniqueId2() {
if (this.uniqueId2!= null) {
return this.uniqueId2; //CHILD
}
return super.getUniqueId2(); // (SUPER)
}
然后,在我获取登录用户信息的方法中,接受所选用户的字符串并执行以下操作:
public @ResponseBody FullUserDetails getLoggedInUserInfo(
@AuthenticationPrincipal MyImplementationOfUserDetails user,
String selectedUsername)
MyImplementationOfUserDetails user2 = getUserInfo(selectedUsername);
user.setAuthorities(user2.getAuthorities());
user.setUniqueId1(user2.getUniqueId1());
user.setUniqueId2(user2.getUniqueId2());
通过这种方式,我能够“更改”权限和唯一 id 属性,否则这些属性是不可更改的,因为它们在父类中是私有(private)的,并且通常只能通过构造函数访问。 我尝试在 UserDetails 实现中创建一个新的构造函数,但是当我创建一个新的 @AuthenticationPrincipal 时,它不会覆盖 session 中的构造函数。我认为需要一个新的构造函数将是最正确的方法。如何使用新的 UserDetails 对象覆盖 session 中的 @AuthenticationPrincipal?或者是否有一种我没有想到的更好的方法?我只想将所选子用户的新权限和唯一ID信息放入@AuthenticationPrincipal中。下次我获取 @AuthenticationPrincipal 时,它将包含该信息。
不获取新信息并将其放入@AuthenticationPrincipal的后果是网页行为将是错误的。主要是因为所选用户的权限级别不正确。
我试图打电话:
SecurityContextHolder.getContext().setAuthentication(newAuthenticationObjectHere);
但是调用 setAuthentication() 后我没有看到变化...
我能够看到更改的唯一方法是直接调用从 @AuthenticationPrinciple 检索的 MyImplementationOfUserDetails 对象中的 setter 。
最佳答案
抱歉,很困惑,但主要思想几乎可以理解。
我认为您会不断地想出一个想法来计算帐户之间的所有复杂关系,然后为最终帐户提供所需的权限并提供对某些资源的访问权限。
如果要更改提供资源访问权限而不操纵帐户关系的逻辑会怎样?还有一个非常重要的链 - 使用像 Spring OAuth2 这样的远程/分布式授权服务器?有了它,您可以拥有任何帐户和范围的权限(!)。根据组织条件,帐户可以具有不同的范围。您的最终资源(通常是 Controller 方法)已按范围进行预身份验证。按照这个思路,可以将基于账户具体提供访问的逻辑分开,用账户来实现DB中的所有逻辑。
也许这对您的项目来说是错误的想法,但对我来说它是有效的 - 我根据客户的条件更改客户的范围,但不会在运行时操纵他们的数据和关系。
关于java - 带嵌套帐户的 Spring Security,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59491062/