我对 Spring 和 Spring Security 真的很陌生。我正在阅读有关 Spring Security 的内容,它提出了主体的概念,它应该是当前登录的用户。但是,如果我们有多个当前登录用户怎么办?那么,我的问题是,春季安全的主要负责人究竟是什么?
例如,我已经阅读了本教程:
http://www.mkyong.com/spring-security/get-current-logged-in-username-in-spring-security/
他们似乎考虑到当前只有一个登录用户,但这种情况并不常见。
如何检索特定用户?以及如何区分正在执行请求的用户?
主体是当前登录的用户。但是,您通过绑定到当前线程的安全上下文来检索它,因此它也绑定到当前请求及其会话。
SecurityContextHolder.getContext()
通过 ThreadLocal
变量在内部获取当前的 SecurityContext
实现。因为请求绑定到单个线程,这将为您提供当前请求的上下文。
为简化起见,您可以说安全上下文在会话中,并且包含用户/主体和角色/权限。
如何检索特定用户?
你没有。所有 API 都旨在允许访问用户和当前请求的会话。让用户 A 成为 100 个当前经过身份验证的用户之一。如果 A 向您的服务器发出请求,它将分配一个线程来处理该请求。如果您随后执行 SecurityContextHolder.getContext().getAuthentication()
,您将在此线程的上下文中执行此操作。默认情况下,您无法从该线程中访问由不同线程处理的用户 B 的上下文。
以及如何区分正在执行请求的用户?
您不必这样做,这就是 Servlet 容器为您所做的。
Principal 的简要定义:
Principal 代表用户的身份。
它可以是在简单级别上具有用户名的 String 对象,也可以是复杂的 UserDetails 对象。
Principal 只是 Java SE 6 的一个旧接口。
由于所有没有默认实现的接口,它简单地定义了一些需要由实现该接口的类实现的方法。
这些方法是
boolean equals(Object another)
Compares this principal to the specified object.
String getName()
Returns the name of this principal.
int hashCode()
Returns a hashcode for this principal.
String toString()
Returns a string representation of this principal.
正如 Java Doc 所述:
该接口表示主体的抽象概念,可用于表示任何实体,例如个人、公司和登录 ID。
简单来说,它只是用来让实现者必须以一种使实体在其他实体之间唯一区分的方式来实现这个接口。此外,getName()
必须返回一个值,通过该值唯一标识一个特定实体并且不会与其他实体发生冲突。因此,如果使用的 Principal
是 UserDetails
类型,则 Principal
的 getName()
返回 UserDetails
的 UserName
。
如果我们看到 Spring 用于 AbstractAuthenticationToken.class
的实现:
public String getName() {
if (this.getPrincipal() instanceof UserDetails) {
return ((UserDetails)this.getPrincipal()).getUsername();
} else if (this.getPrincipal() instanceof AuthenticatedPrincipal) {
return ((AuthenticatedPrincipal)this.getPrincipal()).getName();
} else if (this.getPrincipal() instanceof Principal) {
return ((Principal)this.getPrincipal()).getName();
} else {
return this.getPrincipal() == null ? "" : this.getPrincipal().toString();
}
}
同样重要的是要提到:
abstract class AbstractAuthenticationToken implements Authentication
和
interface Authentication extends Principal
Principal
接口还确保实现者将实现 equals()
和 hashCode()
,这很有意义,因为代表组织或公司或个人的 Principal 实体必须有某种方式与其他实体进行比较。
不定期副业成功案例分享
root
和admin
的登录用户,并且我有一个请求映射为/users/{username}
的控制器。进一步假设root
在客户端的 URLwww.host.com:3000/users/root
上使用他的帐户进行游戏。此时,我猜已经为 root 生成了一个会话 ID。如果它现在尝试向www.host.com:3000/users/admin
发出请求,例如通过手动更改 URL,并且管理员也已连接并从另一台计算机登录,在这种情况下会发生什么情况?