【问题标题】:What's the "principal" in Spring Security?Spring Security 中的“主体”是什么?
【发布时间】:2016-09-26 17:27:54
【问题描述】:

我对 Spring 和 Spring Security 非常陌生。我正在阅读有关 Spring Security 的内容,它提出了 principal 的概念,它应该是当前登录的用户。但是,如果我们有多个当前登录用户怎么办?那么,我的问题是,那么 Spring Security 的主体到底是什么?

例如,我已经阅读了本教程:

http://www.mkyong.com/spring-security/get-current-logged-in-username-in-spring-security/

他们似乎考虑到当前只有一个登录用户,但这种情况并不常见。

如何检索特定用户?以及如何区分正在执行请求的用户?

【问题讨论】:

标签: java spring spring-security


【解决方案1】:

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() 必须返回一个值,通过该值唯一标识一个特定实体并且不会与其他实体发生冲突。 因此,如果使用的PrincipalUserDetails 类型,那么PrincipalgetName() 将返回UserNameUserName

如果我们看到 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 实体必须有某种方式与其他实体进行比较.

【讨论】:

    【解决方案2】:

    Principal 的简要定义:

    Principal代表用户的身份。

    它可以是一个具有简单级别用户名的 String 对象,也可以是一个复杂的 UserDetails 对象。

    【讨论】:

      【解决方案3】:

      主体当前登录的用户。但是,您通过绑定到当前线程的安全上下文来检索它,因此它也绑定到当前请求及其会话。

      SecurityContextHolder.getContext() 在内部通过ThreadLocal 变量获取当前的SecurityContext 实现。因为请求绑定到单个线程,这将为您提供当前请求的上下文。

      为简化起见,您可以说安全上下文在会话中,并且包含用户/主体和角色/权限。

      如何检索特定用户?

      你没有。所有 API 都旨在允许访问当前请求的用户和会话。假设用户 A 是 100 个当前经过身份验证的用户之一。如果 A 向您的服务器发出请求,它将分配一个线程来处理该请求。如果您随后执行SecurityContextHolder.getContext().getAuthentication(),您将在此线程的上下文中执行此操作。默认情况下,您无法从该线程中访问由不同线程处理的用户 B 的上下文。

      我如何区分正在执行请求的用户?

      您不必这样做,这就是 Servlet 容器为您做的事情。

      【讨论】:

      • 那么,我随之而来的问题是:spring 如何区分会话和用户?我想这需要对 Spring 有更深入的了解……
      • 谢谢!不错的答案。我只有一个疑问,这来自于我在创建 Web 应用程序等方面的经验减少。但在此之前,让我试着解释一下我认为我知道的事情。据我所知,可以使用会话 ID 来增强 HTTP 请求。 Tomcat(或其他)可能使用此信息来区分用户和请求。 Principal 是当前上下文的当前登录用户。要了解存在登录用户(主体),可能必须与会话号相关联。
      • 现在,假设我有两个名为rootadmin 的登录用户,并且我有一个请求映射为/users/{username} 的控制器。进一步假设root 在客户端使用他的帐户在URL www.host.com:3000/users/root 上玩。此时,我猜已经为 root 生成了一个会话 ID。如果它现在尝试通过手动更改例如 URL 来向www.host.com:3000/users/admin 发出请求,并且管理员也已连接并从另一台计算机登录,在这种情况下会发生什么?
      • 我猜服务器不允许这样做,因为请求可能不包含正确的信息,即正确的会话 id?
      • @nbro 使用 RestController 只需添加 Principal arg like here,Spring 会自动填充它,您可以进行任何所需的安全检查。 (例如,如果 P 是“root”,但试图看到“admins”页面会抛出 403 错误,但允许他尝试访问他的页面。)请参阅第 15.3.2.3 节 here 了解您可以选择 Spring 将自动为您填充。
      猜你喜欢
      • 2015-12-04
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 2011-02-02
      • 1970-01-01
      • 2019-12-16
      相关资源
      最近更新 更多