我已经实现了一个 JAAS 登录模块
,它与 Spring 4 和 Struts 2.3 配合使用效果很好。这个相同的登录模块
也可以通过 Tomcat 8.0/8.5 中的 Servlet 过滤器
调用,以对 Spring 框架之外的 Servlet 请求进行身份验证和授权。
< code>LoginModule使用< code > Java . security . ACL . group 的简单实现,并使用< code > Java . security . principal 的两个简单实现来分隔用户和角色。我所说的“简单”是指满足接口的最小实现。
“User”实现将< code>name属性映射到一个唯一的用户名(实际上是一个电子邮件地址)。由于电子邮件地址是唯一的,但可能会改变,帐户数据库包含一个唯一的帐户标识符(GUID ),用于分配组、角色和记录服务请求(同时也匿名化我们的用户)。在我的模型中,< code>AccountIdentifier有自己的类。本质上,我有两个惟一的帐户标识符,但是由于电子邮件地址需要提供给< code>LoginModule进行身份验证,所以它最终成为用户主体的基础。
帐户标识符当前没有传播到登录模块中的主题,但现在我需要它来记录服务请求。
我认为通过主题
提供帐户标识符有两种方式,但我不确定JAAS的最佳实践是什么:
Principal
实现,以包括在LoginModule.commit()
LoginModule()期间设置的“accountIdentifier”属性AccountIdentifier
作为一个单独的主体
来实现,该主体在
0.05主题中
第一个选项是最简单的,但这似乎也违背了将个人身份信息与账户隔离的目的(这是我需要做的事情,以满足即将到来的欧盟数据保护法要求)。
我是否应该在Subject中添加“User”主体(包含电子邮件地址的主体)?
JAAS和Servlet规范在身份验证和用户原则方面存在一些不兼容性。正因为如此,Spring使用了不同于Tomcat的JAAS集成方法。
这个答案记录了一种以同时容纳Tomcat和Spring的方式实现JAAS登录模块的综合方法。
为清楚起见,从问题中复制了实现用户原则的两个选项:
选项 1 具有将不同形式的个人身份信息连接在一起的不幸副作用,这在某些情况下可能违反欧洲 GDPR 法规(会话可以序列化到磁盘上,并且此信息会随之而来)。
选项2分离出个人身份信息,但必须以克服Servlet规范和Tomcat的JAAS实现中的几个限制的方式实现。
下面详细描述了这些限制,粗体部分总结了要点。
Tomcat 8.5 JAAS领域文档指出:
使用JAASRealm使开发人员能够将几乎任何可以想象的安全领域与Tomcat的CMA相结合。
但接着又说:
虽然在JAAS中没有指定,但是您应该创建单独的类来区分用户和角色,扩展< code > javax . security . principal ,以便Tomcat可以判断从您的登录模块返回的主体中哪些是用户,哪些是角色(请参见< code > org . Apache . catalina . realm . JAAS realm )。无论如何,返回的第一个主体总是被视为用户主体。
注意,上面的Tomcat文档使用了短语“用户主体”。尽管JAAS API建议将用户和角色实现为扩展javax.security.Principal的不同类,但这与Servlet规范不兼容,因为http Servlet request . getuser Principal()只允许返回单个主体:
返回一个< code > javax . security . principal 对象,其中包含当前已通过身份验证的用户的名称。如果用户尚未通过身份验证,该方法将返回null。
对上述文档的严格阅读表明,它应该包含“...当前认证用户的名字”,但是为了满足我最初的目标,我把它解释为“...被认证主体的任何名称或标识符”。这更接近于com . sun . security . auth . user principal文档(即“由用户名或帐户名标识的用户主体”)。
由于Tomcat的< code>JAASRealm和Servlet规范的< code>HttpServletRequest中的上述限制,如果帐户标识符要通过< code>ServletFilter(它只能访问当前会话、请求和响应)传播到请求中,那么它必须包含在第一个< code>Principal中(因此,原始问题中的选项1将满足此要求,或者只有在选项2首先出现并且我不需要原始用户名时,才满足此要求)我相信我真正需要的是帐户标识符,所以我现在坚持使用第二个选项,我将“EmailAddressPrincipal”传递给< code>MyLoginModule,并通过< code>Subject接收一个“AccountIdentifierPrincipal”(即< code>MyLogin.commit()将“AccountIdentifierPrincipal”添加为第一个主体)。
JAASRealm
文档实际上在原理的确切顺序方面略有矛盾,这取决于您正在阅读的章节:
当这个领域遍历Subject.getPrincipals()返回的主体时,它将识别与“用户类”列表匹配的第一个主体作为该用户的主体
与。
无论如何,返回的第一个主体始终被视为用户主体。
本质上,如果我要创建一个ServletFilter
来模仿JAASRealm
所做的事情,身份验证将如下所示(特别注意迭代器):
final LoginContext loginContext = new LoginContext(MyLoginModule.JAAS_REALM, new DefaultCallbackHandler(username, password));
loginContext.login();
final Subject subject = loginContext.getSubject();
request.getSession().setAttribute("AUTH_USER_PRINCIPAL", subject.getPrincipals(AccountIdentifierPrincipal.class).iterator().next());
request.getSession().setAttribute("AUTH_ROLE_PRINCIPALS", subject.getPrincipals(MyRolePrincipal.class));
不幸的是,这与 javax.security.auth.Subject 的构造函数直接冲突,该构造函数要求将 java.util.Set 用作主体的支持集合。此外,Set.迭代器 () 文档指出:
元素不按特定顺序返回(除非此集是某个提供保证的类的实例)。
我们最早对主题
的访问是在LoginModule.initialize()
方法中,不幸的是,这是在LoginContext
的内部某处调用的东西(我认为)。这意味着我们无法控制Set
的确切子类,该子类用作校长
的后备集合,因此无法控制它们的排序。当它到达ServletFilter
时,它是一个同步集,因此甚至不清楚原始类是什么,或者是否发生了重新排序。
所有这些都表明,为了让< code>JAASRealm按预期工作,只能提供一个用户主体。在中间层的任何地方都没有接口来清楚地建立< code > Subject < code > principal 的顺序。
使用JAASRealm
时,在提交
期间,应仅将声明的User类型的一个主体
添加到主题
。
使用< code>JAASRealm时,避免使用多个用户类名。
违反上述两个规则可能会导致未定义和/或不一致的行为。
出于选项2的考虑,我避免使用< code>JAASRealm,因为根据上面所有的文档,它并不忠实于JAAS。这使我回到了纯粹的< code>ServletFilter方法。
主题包含授权所需的所有内容:多个用户主体、角色和 ACL 组。不幸的是,这个类只能部分序列化,这意味着我不能只是将类包装为主体
并返回它。
为了满足Spring的DefaultJaasAuthenticationProvider,需要实现一个AuthorityGranter来将< code>Principal映射到角色名——它提供了对如何执行映射的完全控制。
因为< code>AuthorityGranter在Spring框架之外不可用,所以我还实现了一个< code>ServletFilter,它使用类似的方法为我的非Spring webapp映射角色。我暂时使用< code > http servlet requestwrapper 从会话属性(在身份验证期间存储在会话中)读取主体和角色,并覆盖getUserPrincipal和isUserInRole。最后,我将重新访问JAASRealm,看看它是否包含任何处理这部分的功能,但我还没有完全实现。
我有两个表审查和bedrijfsgegevens。Review表有一个主键(reviewId)和一个外键(bedrijfId)。BedrijfId是Bedrijfsgegevens表中的主键(作为Id)。我遇到了这个问题,因为我试图在Review表中添加一个bedrijfId,而Bedrijfgegevens表中不存在这个行,因此得到了一个异常。 我尝试使用@manytoone和@joincolu
我在API上使用Vertx框架对JWT令牌进行授权。在用户被授权并且令牌被解密之后,我想要访问令牌的内容,尤其是令牌中的“userId”字段。 最初,我是用作为作为以下内容来访问它的:
我使用的是Netbeans IDE 8.0.2和eclipselink 2.5.2。下面是打开连接时出现的异常,问题是这种情况并不是每次都发生。异常“Departmento”中描述的实体完全遵循其他类的模式,即我们的系统已经包含大约500个实体类,只有在新的类中才发生此异常。这个实体是由Netbeans的“实体类从数据库”选项生成的,并添加到持久化XML... 由:javax.Persistenc
我必须写一个程序,它将接受Hashmap格式的body。我已经用Hashmap值创建了HttpEntity 我面临以下例外: 异常线程"main"org.springframework.web.client.RESTClientExcture: No HttpMessageConzer for[java.util.HashMap]atorg.springframework.web.client.R
当我使用Office 365的配置api时(通过连接msolservice或https://provisioningapi.microsoftonline.com/provisioningwebservice.svc)我正在使用用户名和密码。当我连接时,我会自动使用powershell或通过web服务和office365部署(如联合/解除联合本地域) 我面临的问题是密码最终会过期,我的服务会中断,
我正在尝试为一个名为Zulip的开源项目构建python api,我一直遇到下面截图所示的相同问题。 我正在运行python3,我的pip版本是10.0。0.正在讨论的文件是而混乱的代码是当属性可用于安装软件包。 现在,我知道这个构建应该成功,因为它是一个开源项目,但是我已经尝试了几个小时来修复关于的依赖问题。 任何帮助将不胜感激。