【问题标题】:Spring Security Requirements and questionsSpring 安全要求和问题
【发布时间】:2013-06-11 02:00:19
【问题描述】:
我正在开发一个使用 Spring MVC 和 Spring REST 的应用程序,它分为 2 个服务器,后端是 Spring REST 接口,前端是普通的 SPRING MVC 应用程序。然而,我有一些安全要求,尤其是对于 MVC 服务器前端,例如
- 每个用户只有一个活动会话
- 指定时间后的会话超时
- 能够从应用程序的表单创建新角色,并将这些角色应用于在运行时动态访问的 URL,而不是硬编码到配置中。
我的问题是
- 有没有办法实现自定义登录模块,该模块将对用户进行身份验证,但仍然使用 Spring Security 来管理登录和注销后的访问控制。
- 我看到的所有示例都使用在 Spring 配置文件中配置的预定义角色,但是我们的要求是我们不知道系统中的角色以及在部署时允许他们访问的 URL,所有这些都是由管理员通过 UI 配置的,所以问题是我可以使用任何示例来查看如何在 Spring Security 中处理这些问题。
- 最后是上面提到的单会话要求。
任何指针将不胜感激。
【问题讨论】:
标签:
java
spring-security
session-timeout
【解决方案1】:
1) 有没有办法实现自定义登录模块,该模块将对用户进行身份验证,但仍然使用 Spring Security 来管理登录和注销后的访问控制。
是的。您可以通过实现 org.springframework.security.authentication.AuthenticationProvider 并使其成为 bean(对其进行注释或在 XML 中)来提供自己的身份验证机制:
@Service("myAuthenticationProvider") 公共类
TangoAuthenticationProvider 实现 AuthenticationProvider{
@Override
public boolean supports(Class<?> authentication) {
//your code
}
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
//your code
}
然后,并指示 Spring 安全性使用它(在您的安全性上下文中):
<authentication-manager>
<authentication-provider ref="tangoAuthenticationProvider" />
</authentication-manager>
见this question,当然还有spring security doc。
2) 动态创建的角色:我无法回答 thios 部分,没有这方面的经验。
3) 单次会话要求
也许 Spring Security 中内置了这样一种机制(您必须研究一下),但我认为您可以使用简单的会话侦听器和上述自定义身份验证机制来实现它:
- 将会话 ID 字段添加到您的用户实体(或其他地方,但以某种方式将您的用户 ID 与会话 ID 相关联)
-
创建一个服务,允许存储与其 id 关联的会话的引用,并通过其 id 提供对会话的访问。您可以使用静态哈希映射,或者单例,或者更好的 Spring 服务 bean,其接口大致如下(我们称其为会话存储库):
public void putSession(String id, HttpSession session);
public HttpSession getSessionById(String id);
在您的身份验证提供程序中,成功登录后,将用户的会话 id 字段设置为当前会话 id
- 在身份验证逻辑中,如果用户的 sessionId 字段不为空,则禁止身份验证(那么您不需要对会话机制事物的引用),或者更可能是真正的要求,继续通过使用用户的 sessionId 字段的值从会话存储库中获取它来使用户的其他正在进行的会话无效
- 在会话监听器中:
在创建会话时:将会话存储在会话存储库中
会话删除:如果有登录用户,清除其 sessionId 字段;清除对会话的引用以避免内存泄漏。
这是与安全相关的敏感代码(跨会话内容),因此应该非常仔细地编写和测试它!
希望对你有帮助。
【解决方案2】:
您可以使用表单登录。
为了创建动态角色,你可以用一种方法实现 UserDetailsService 接口,
public UserDetails loadUserByUsername(String userId)
throws UsernameNotFoundException, DataAccessException
{
...
/*
fetch your role information every time the user re-login
you can store the new role in the database and fetch it from here
*/
}
之后,您可以使用数据库角色配置您的 spring-security 文件以进行身份验证/授权
对于每个用户要求的单次访问,请尝试将所有用户 - sessionid 对保存在数据库或应用程序级别的哈希图中。有一个spring ContextLoaderListener,(钩子下的HttpSessionListener)因此您可以从监听器的应用程序中添加/删除user-sessionid对。