在我的 Spring MVC Web 应用程序中,某些区域只能由具有足够权限的用户访问。我需要能够允许用户以不同的用户身份登录才能使用这些页面(有点像覆盖),而不仅仅是“拒绝访问”消息。
我如何使用 Spring Security 做到这一点?
这是我想要的流程,有更多细节:
- 用户 A 从外部应用程序进入页面 X 并通过 header 进行身份验证
- 用户 A 没有使用页面 X 的权限,因此被带到登录屏幕,并显示一条消息,指示他们必须以具有足够权限的用户身份登录才能使用此页面
- 用户 B 登录并拥有足够的权限,然后被带到页面 X。
注意:页面 X 有一个大而长的查询字符串需要保留。
我如何使用 Spring Security 做到这一点?
这是我的 spring 安全配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<debug />
<global-method-security pre-post-annotations="enabled">
<!-- AspectJ pointcut expression that locates our "post" method and applies
security that way <protect-pointcut expression="execution(* bigbank.*Service.post*(..))"
access="ROLE_TELLER"/> -->
</global-method-security>
<!-- Allow anyone to get the static resources and the login page by not applying the security filter chain -->
<http pattern="/resources/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/img/**" security="none" />
<http pattern="/js/**" security="none" />
<!-- Lock everything down -->
<http
auto-config="true"
use-expressions="true"
disable-url-rewriting="true">
<!-- Define the URL access rules -->
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/about/**" access="permitAll and !hasRole('blocked')" />
<intercept-url pattern="/users/**" access="hasRole('user')" />
<intercept-url pattern="/reviews/new**" access="hasRole('reviewer')" />
<intercept-url pattern="/**" access="hasRole('user')" />
<form-login
login-page="/login" />
<logout logout-url="/logout" />
<access-denied-handler error-page="/login?reason=accessDenied"/>
<!-- Limit the number of sessions a user can have to only 1 -->
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
</http>
<authentication-manager>
<authentication-provider ref="adAuthenticationProvider" />
<authentication-provider>
<user-service>
<user name="superadmin" password="superadminpassword" authorities="user" />
</user-service>
</authentication-provider>
</authentication-manager>
<beans:bean id="adAuthenticationProvider" class="[REDACTED Package].NestedGroupActiveDirectoryLdapAuthenticationProvider">
<beans:constructor-arg value="[REDACTED FQDN]" />
<beans:constructor-arg value="[REDACTED LDAP URL]" />
<beans:property name="convertSubErrorCodesToExceptions" value="true" />
<beans:property name="[REDACTED Group Sub-Tree DN]" />
<beans:property name="userDetailsContextMapper" ref="peerReviewLdapUserDetailsMapper" />
</beans:bean>
<beans:bean id="peerReviewLdapUserDetailsMapper" class="[REDACTED Package].PeerReviewLdapUserDetailsMapper">
<beans:constructor-arg ref="UserDAO" />
</beans:bean>
</beans:beans>
我使用的是 Spring Security 3.1 Active Directory 连接功能的略微修改版本。这些修改只是加载用户的所有 组,包括通过组嵌套到达的组,而不仅仅是用户直接属于的组。我还使用了一个自定义用户对象,其中嵌入了我的应用程序的用户对象,以及一个自定义 LDAP 映射器,它执行正常的 LDAP 映射,然后添加到我的用户中。
有一种尚未实现的特殊身份验证方案,其中用户根据从外部应用程序(或通过 Kerberos)以单点登录方式传递的用户名进行身份验证。
最佳答案
您如何检查角色?
如果您像这样在安全上下文中定义它们:
<intercept-url pattern="/adminStuff.html**" access="hasRole('ROLE_ADMIN')" />
您可以设置 defaultFailureUrl
在你的 SimpleUrlAuthenticationFailureHandler
当权限较低的用户尝试访问安全 URL 时,FaliureHandler
应该将您重定向到 defaultFailureUrl
这可能是您的登录页面。
你可以注入(inject)一个FaliureHandler
在filter在 FORM_LOGIN_FILTER
位置。
<bean id="myFaliureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="http://yourdomain.com/your-login.html"/>
</bean>
<bean id="myFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationFailureHandler" ref="myFaliureHandler"/>
</bean>
<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>
在评论中回答 1)。
考虑到您的命名空间配置,这比我想象的要多一些工作。
您需要做的是删除 <form-login>
定义,而不是添加“自定义”UsernamePasswordAuthenticationFilter
(这是处理 <form-login>
元素的过滤器)。
您还需要删除 <access-denied-handler>
.
所以你的配置看起来像这样:
<bean id="myFaliureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="http://yourdomain.com/your-login.html"/>
</bean>
<bean id="myFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationFailureHandler" ref="myFaliureHandler"/>
<!-- there are more required properties, but you can read about them in the docs -->
</bean>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login"/>
</bean>
<http entry-point-ref="authenticationEntryPoint" auto-config="false">
<!-- your other http config goes here, just omit the form-login element and the access denied handler -->
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>
一般也看看spring docs on custom filters ,如果你还没有。我们目前在我当前的公司中使用此配置,如果用户在页面上没有所需的权限,则强制用户重新登录。
关于java - 我如何允许用户使用 Spring Security 覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7558943/