我可以将自己的User对象推送到Spring的SecurityContext中吗?

时间:2014-03-11 18:33:48

标签: java spring spring-security

我是Spring Security的新手,并且已经遵循了一些基本的方法来让Spring Security在我的应用程序中运行,但是现在我正在尝试查看是否有办法将我自己的User对象添加到登录/身份验证时Spring的SecurityContext。

我的安全性目前已配置为使用JdbcDaoImpl:

<authentication-manager alias="authenticationManager">
    <authentication-provider user-service-ref="com.ia.security.SpringSecurityDao" />
</authentication-manager>

<beans:bean id="com.ia.security.SpringSecurityDao" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <beans:property name="usersByUsernameQuery">
        <beans:value>select username,password,enabled 
        from user 
        where username = ?
        </beans:value>
    </beans:property>
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="enableGroups" value="true" />
    <beans:property name="enableAuthorities" value="false" />
    <beans:property name="groupAuthoritiesByUsernameQuery">
        <beans:value>SELECT R.ID, R.NAME, P.NAME
            FROM ROLE R
            JOIN USER_ROLE UR on R.id = UR.role_id
            JOIN USER U on U.id = UR.user_id
            JOIN ROLE_PERMISSION RP ON RP.role_id = R.id
            JOIN PERMISSION P ON P.id = RP.permission_id
            WHERE U.username=?
        </beans:value>
    </beans:property>
</beans:bean>

我意识到我可以从SecurityContext中检索Principal对象并获取用户名并重新查询给定用户名的数据库,但我认为简单地存储我的整个User对象会更容易在SecurityContext中,只要我在整个应用程序中需要它,就可以轻松访问它,而不是只在UserDetails对象中存储用户名,密码和已启用的字段。

我查看了UserDetailsS​​ervice,更具体地说是JdbcDaoImpl类,但不完全确定最佳的继续方法。如果我只是通过调用super.loadUserByUsername来覆盖/扩展loadUserByUsername方法来返回我自己的UserDetails对象就够了吗?那么我能够做SecurityContextHolder.getContext().getAuthentication().getDetails()并将其投射到我自己的对象上吗?

我在StackOverflow上发现了与此相关的其他帖子,但大多数帖子似乎忽略了与从DB检索到的权限和角色有关的任何内容,因此我不确定这是否是最佳方式。

1 个答案:

答案 0 :(得分:2)

答案简短: 是的,你可以按计划完成。请记住,某些功能(如“hasRole”)会检查权限列表,而不是默认情况下的用户详细信息。

答案很长: 将用户对象保存在会话中保存的securitycontext中可能会产生一些副作用。 使用休眠时尤其如此。懒惰的例外吗? ;) 我们首先走了这条路线,后来几次打电话给一些LIE发生了,跟进起来非常棘手。使用OpenSessionInView过滤器,我们认为我们是安全的,但这是错误的,因为在下一个请求中会话消失了。所以我们从用户那里加载了更多相关的对象,但它仍然存在。稍后:)

我们有三种选择。要么在每个请求上合并用户对象,要在用户详细信息中创建仅包含必要安全信息的pojo,要么只保留主体(登录)在安全上下文中,并在需要时加载用户对象。

我们选择了第三个解决方案,因为hibernate使用二级缓存做得很好。 作为副作用,安全性现在更加可靠,因为Spring安全性现在在每个请求上获得用户的最新版本,并且不适用于“陈旧”用户角色。

因此,如果您不使用休眠,或者您可以保证不会发生任何LIE,请选择解决方案一或两个。否则我会推荐我们的方法。