不过一般我们在管理系统时都会分前台与后台,也就是说,前台与后台的登录入口与注销地址都是不一样的,那么该如何使用SpringSecurity实现呢,参考了一些网络上的例子,将之前的小应用做了如下修改:
applicationContext-security.xml
- <? xml version = "1.0" encoding = "UTF-8" ?>
- < beans:beans xmlns = "http://www.springframework.org/schema/security"
- xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:p = "http://www.springframework.org/schema/p"
- xmlns:aop = "http://www.springframework.org/schema/aop" xmlns:context = "http://www.springframework.org/schema/context"
- xmlns:jee = "http://www.springframework.org/schema/jee" xmlns:tx = "http://www.springframework.org/schema/tx"
- xmlns:util = "http://www.springframework.org/schema/util" xmlns:mvc = "http://www.springframework.org/schema/mvc"
- xmlns:tool = "http://www.springframework.org/schema/tool" xmlns:beans = "http://www.springframework.org/schema/beans"
- xsi:schemaLocation ="
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
- http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool-3.0.xsd
- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"
- default-lazy-init = "true" >
- <!-- 不需要进行认证的资源,3.0之后才改为这样配置 -->
- < http security = "none" pattern = "/**/login.do" />
- <!-- 因为要使用自己的权限验证规则,所以这里要配置access-decision-manager-ref
- 实际上,我只是在accessDecisionManager中增加了一个投票器,其它的属性都比较简单,不多说了 -->
- <!-- 另外,为了实现前后台访问使用不同的登录地址,这里增加了一个entry-point-ref-->
- < http entry-point-ref = "loginUrlEntryPoint" access-decision-manager-ref = "accessDecisionManager" access-denied-page = "/notaccess.jsp" >
- < intercept-url pattern = "/demo.do*" access = "IS_AUTHENTICATED_REMEMBERED" />
- <!-- 后台地址拦截 -->
- < intercept-url pattern = "/admin/**/*.do*" access = "AD_HODLE" />
- <!-- 前台地址拦截 -->
- < intercept-url pattern = "/**/*.do*" access = "HODLE" />
- < session-management >
- < concurrency-control max-sessions = "1" />
- </ session-management >
- <!-- 登录过滤器 -->
- < custom-filter before = "FORM_LOGIN_FILTER" ref = "loginFilter" />
- < custom-filter position = "FORM_LOGIN_FILTER" ref = "adminLoginFilter" />
- <!-- 注销过滤器 -->
- < custom-filter before = "LOGOUT_FILTER" ref = "logoutFilter" />
- < custom-filter position = "LOGOUT_FILTER" ref = "adminLogoutFilter" />
- </ http >
- <!-- 认证切入点,这里使用它的目的是保证当用户登录之前就访问前后台时,会跳转到不同的登录页面 -->
- < beans:bean id = "loginUrlEntryPoint" class = "com.piaoyi.common.security.LoginUrlEntryPoint" />
- <!-- 登录过滤器,验证前台用户 -->
- < beans:bean id = "loginFilter"
- class = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter" >
- < beans:property name = "authenticationManager" ref = "authenticationManager" />
- < beans:property name = "authenticationFailureHandler" ref = "failureHandler" />
- < beans:property name = "authenticationSuccessHandler" ref = "successHandler" />
- < beans:property name = "filterProcessesUrl" value = "/j_spring_security_check" />
- </ beans:bean >
- < beans:bean id = "failureHandler"
- class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" >
- < beans:property name = "defaultFailureUrl" value = "/login.do?login_error=1" />
- </ beans:bean >
- < beans:bean id = "successHandler"
- class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler" >
- < beans:property name = "alwaysUseDefaultTargetUrl" value = "true" />
- < beans:property name = "defaultTargetUrl" value = "/demo.do" />
- </ beans:bean >
- <!-- 登录过滤器,验证后台用户 -->
- < beans:bean id = "adminLoginFilter"
- class = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter" >
- < beans:property name = "authenticationManager" ref = "authenticationManager" />
- < beans:property name = "authenticationFailureHandler" ref = "adminFailureHandler" />
- < beans:property name = "authenticationSuccessHandler" ref = "adminSuccessHandler" />
- < beans:property name = "filterProcessesUrl" value = "/j_spring_security_check" />
- </ beans:bean >
- < beans:bean id = "adminFailureHandler"
- class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" >
- < beans:property name = "defaultFailureUrl" value = "/admin/login.do?login_error=1" />
- </ beans:bean >
- < beans:bean id = "adminSuccessHandler"
- class = "org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler" >
- < beans:property name = "alwaysUseDefaultTargetUrl" value = "true" />
- < beans:property name = "defaultTargetUrl" value = "/admin/frame.do" />
- </ beans:bean >
- <!-- 注销过滤器,完成前台用户注销时的定向功能 -->
- < beans:bean id = "logoutFilter" class = "org.springframework.security.web.authentication.logout.LogoutFilter" >
- < beans:constructor-arg value = "/login.do" />
- < beans:constructor-arg >
- < beans:list >
- < beans:bean class = "org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
- </ beans:list >
- </ beans:constructor-arg >
- < beans:property name = "filterProcessesUrl" value = "/j_spring_security_logout" />
- </ beans:bean >
- <!-- 注销过滤器,完成后台用户注销时的定向功能 -->
- < beans:bean id = "adminLogoutFilter" class = "org.springframework.security.web.authentication.logout.LogoutFilter" >
- < beans:constructor-arg value = "/admin/login.do" />
- < beans:constructor-arg >
- < beans:list >
- < beans:bean class = "org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
- </ beans:list >
- </ beans:constructor-arg >
- < beans:property name = "filterProcessesUrl" value = "/admin/j_spring_security_logout" />
- </ beans:bean >
- <!-- Automatically receives AuthenticationEvent messages -->
- < beans:bean id = "loggerListener"
- class = "org.springframework.security.authentication.event.LoggerListener" />
- <!-- 认证管理器,使用自定义的UserDetailsService,并对密码采用md5加密-->
- < authentication-manager alias = "authenticationManager" >
- < authentication-provider user-service-ref = "userService" >
- < password-encoder hash = "md5" />
- </ authentication-provider >
- </ authentication-manager >
- < beans:bean id = "userService" class = "com.piaoyi.common.security.UserService" />
- <!-- 访问决策管理器,这里使用AffirmativeBased,并加入一个自定义的投票器DynamicRoleVoter -->
- < beans:bean id = "accessDecisionManager"
- class = "org.springframework.security.access.vote.AffirmativeBased" >
- < beans:property name = "decisionVoters" >
- < beans:list >
- < beans:bean class = "org.springframework.security.access.vote.RoleVoter" />
- < beans:bean
- class = "org.springframework.security.access.vote.AuthenticatedVoter" />
- < beans:bean class = "com.piaoyi.common.security.DynamicRoleVoter" />
- </ beans:list >
- </ beans:property >
- </ beans:bean >
- </ beans:beans >
说明:
1.为了实现不同的登录验证,这里显示声明了登录过滤器与注销过滤器,并指定相应过滤器的位置。
2.因为我们自己来指定了登录过滤器与注销过滤器,所以就不能在<http>中设置auto-config="true"
3.为了区分开不同的登录页面,就需要在<http>中配置认证切入点“entry-point-ref”,认证切入点的作用是当请求被拦截时该如何处理,这里处理为跳转到各自的登录页面
4.这里理想化的将前台用户与后台用户都使用同一个userService进行管理,即表示都存储在同一张用户表中,对于前后台用户不在同一张表中的处理,笔者也在研究中。
LoginUrlEntryPoint.java
- public class LoginUrlEntryPoint implements AuthenticationEntryPoint {
- public void commence(HttpServletRequest request, HttpServletResponse response,
- AuthenticationException authException) throws IOException, ServletException {
- String targetUrl = null ;
- String url = request.getRequestURI();
- if (url.indexOf( "admin" ) != - 1 ){
- //未登录而访问后台受控资源时,跳转到后台登录页面
- targetUrl = "/admin/login.do" ;
- }else {
- //未登录而访问前台受控资源时,跳转到前台登录页面
- targetUrl = "/login.do" ;
- }
- targetUrl = request.getContextPath() + targetUrl;
- response.sendRedirect(targetUrl);
- }
- }