【问题标题】:Shiro Intermittent Subject.getPrincipalShiro 间歇性 Subject.getPrincipal
【发布时间】:2012-10-20 16:26:29
【问题描述】:

我创建了一个 JavaEE6 项目,目前我正在使用 Shiro 进行身份验证和授权。使用本文作为参考 (Using Shiro for Authorization via CDI Interceptors then Easily Test with Arquillian),我已将 Shiro 与 CDI 集成。一切正常,除了有时 Subject.getPrincipal 为空。

此外,调查表明,有时我至少有 2 个 Subject.getSession().getId()。

我是如何遇到问题的:

  1. 登录 -> 使用 sessionA 确定
  2. 单击受保护的链接 (pageA) -> ok
  3. 尝试在数据库中插入记录失败
  4. 单击相同的安全链接 (pageA) -> 失败,查看生成不同会话 id sessionB 的跟踪
  5. 刷新并刷新,直到页面 (pageA) 正常。在登录 sessionA 期间获得了相同的会话 ID。

可能出了什么问题?

我的 shiro.ini 文件

[main]
saltedJdbcRealm=com.sido.commons.web.security.shiro.JdbcRealmImpl

# any object property is automatically configurable in Shiro.ini file
saltedJdbcRealm.jndiDataSourceName=Portal 

# the realm should handle also authorization
saltedJdbcRealm.permissionsLookupEnabled=true

# If not filled, subclasses of JdbcRealm assume "select password from users where username = ?"
# first result column is password, second result column is salt 
saltedJdbcRealm.authenticationQuery = SELECT password, salt FROM users WHERE username = ?

# If not filled, subclasses of JdbcRealm assume "select role_name from user_roles where username = ?"
saltedJdbcRealm.userRolesQuery = SELECT name FROM roles a INNER JOIN user_roles b ON a.id=b.role_id INNER JOIN users c ON c.id=b.user_id WHERE c.username = ?

# If not filled, subclasses of JdbcRealm assume "select permission from roles_permissions where role_name = ?"
saltedJdbcRealm.permissionsQuery = SELECT action FROM permissions WHERE role = ?

# password hashing specification, put something big for hasIterations
sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha256Matcher.hashAlgorithmName=SHA-256
sha256Matcher.hashIterations=1
saltedJdbcRealm.credentialsMatcher = $sha256Matcher

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
securityManager.sessionManager.sessionDAO = $sessionDAO 

cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager 
cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml
securityManager.cacheManager=$cacheManager 

shiro.loginUrl = /login.xhtml

[urls]
/login.xhtml = authc
/logout = logout

web.xml

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Production</param-value>
</context-param>

<context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>south-street</param-value>
</context-param>

<!-- Welcome page -->
<welcome-file-list>
    <welcome-file>home.xhtml</welcome-file>
</welcome-file-list>

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- Map these files with JSF -->
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

SecurityProducer,一个 Singleton bean,我在其中实例化了安全管理器。它应该对整个应用程序都可用且唯一吗?

@Singleton
public class SecurityProducer {
    @Inject
    private Logger log;
    private SecurityManager securityManager;

    @PostConstruct
    public void init() {
        final String iniFile = "classpath:shiro.ini";
        log.debug("Initializing Shiro INI SecurityManager using " + iniFile);
        securityManager = new IniSecurityManagerFactory(iniFile).getInstance();
        SecurityUtils.setSecurityManager(securityManager);
    }
    ..
}

在初始化时绑定 SecurityManager 或 Subject (Singleton bean) 并不能解决问题。

final String iniFile = "classpath:shiro.ini";
securityManager = new IniSecurityManagerFactory(iniFile).getInstance();
SecurityUtils.setSecurityManager(securityManager);
ThreadContext.bind(SecurityUtils.getSubject()); or ThreadContext.bind(securityManager);

谢谢,
嫖娼

【问题讨论】:

  • 你的 web.xml 看起来像什么?
  • 嗨 jbunting,我已经用 web.xml 更新了我的帖子。请注意,我没有在 web.xml 中添加任何 shiro 标记,因为我在 Singleton bean 中初始化了安全管理器。但我注意到我至少有 2 次使用这种方法。

标签: java-ee-6 shiro


【解决方案1】:

我想我已经通过在此处配置 web.xml 基础解决了间歇性会话问题:http://shiro.apache.org/web.html

目前的外观如下: http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 版本="3.0">

<!-- Welcome page -->
<welcome-file-list>
    <welcome-file>home.xhtml</welcome-file>
</welcome-file-list>
<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<!-- Map these files with JSF -->
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

但这真的是解决方案吗?有什么想法吗?

【讨论】:

  • 已经快 3 年了,我想我今天也遇到了类似的问题 =)... 有什么新见解吗?
  • 你好,你的配置和上面的web.xml一样吗?如果我没记错的话,这解决了我的问题。您可能还想查看 BalusC 关于 Shiro 的文章,只需 google 即可。
  • webl.xml 很好,我在这里弄错了我的问题,与你的没什么可看的。还是谢谢你!
【解决方案2】:

如果您想手动构建主题,您应该将其绑定到调用ThreadContext.bind(subject) 的线程。如果您不这样做,下一次调用 SecurityUtils.getSubject() 将返回新的主题,而不是您之前创建的主题。

例如,在我的应用程序中,我收到了请求中的会话 ID,并从中创建了一个主题。

Subject subject = new Subject.Builder().sessionId(sessionId).buildSubject();
ThreadContext.bind(subject);

【讨论】:

  • 嗨,m1st.kh,我已经在 Singleton bean 中初始化了安全管理器,这意味着我应该在整个应用程序中拥有它的单个实例,对吧?我想知道为什么我在尝试 subject.getPrincipal().getSession().getId() 时至少要进行 2 次会话。关于您的建议,ThreadContext.bind(subject) 是否适用于 javaee6 应用程序?谢谢。
  • 根据您的建议,我在 Singleton Bean 中初始化时尝试绑定 SecurityManager 和 Subject ,但失败了。请参阅我上面编辑的帖子。有时 SecurityUtils.getSubject().getPrincipal() 返回 null 并且我可以看到不同的会话 ID。另请注意,我不是手动构建主题。
猜你喜欢
  • 1970-01-01
  • 2021-07-15
  • 2018-12-16
  • 2019-01-18
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 2011-10-21
  • 2019-05-12
相关资源
最近更新 更多