spring-security 3.0.X, 让ajax login和普通login共存

转载 2015年07月08日 16:04:37

使用spring security时遇到一个问题,有大量的ajax post是需要登录控制的,但是默认的spring-security机制导致post结果返回的是登录页。

 

现在要解决几个问题:

1,ajax post如果需要登录的话,返回需要登录的json消息,前端可以继续处理

2,新建一套ajax login的页面流转,但是不能和原有的login过程冲突,因为其他的非ajax请求还是需要用正常的login。

 

 spring security配置如下:

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:security="http://www.springframework.org/schema/security"  
  5.        xsi:schemaLocation="  
  6.            http://www.springframework.org/schema/beans  
  7.            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  8.            http://www.springframework.org/schema/security  
  9.            http://www.springframework.org/schema/security/spring-security-3.0.xsd">  
  10.   
  11.     <!-- Configure Spring Security -->  
  12.     <!--  
  13.     <security:http auto-config="true">  
  14.         <security:form-login login-page="/login" login-processing-url="/loginProcess"   
  15.             default-target-url="/" authentication-failure-url="/login?login_error=1" />  
  16.         <security:logout logout-url="/logout" logout-success-url="/logoutSuccess" />  
  17.         <security:remember-me key="bookingtest" />  
  18.     </security:http>  
  19.     -->  
  20.     <security:http auto-config="false" entry-point-ref="jilujiaAuthenticationEntryPoint">  
  21.         <!-- 登录过滤器 -->  
  22.              <security:custom-filter before="FORM_LOGIN_FILTER" ref="loginFilter"/>  
  23.              <!-- ajax登录过滤器 -->  
  24.              <security:custom-filter position="FORM_LOGIN_FILTER" ref="ajaxLoginFilter"/>  
  25.              <!-- 只cache get,避免ajax post 被cache -->  
  26.              <security:request-cache ref="httpSessionRequestCache"/>  
  27.              <!-- 注销过滤器 -->  
  28.              <security:logout logout-url="/logout" logout-success-url="/logoutSuccess" />  
  29.              <!-- remember me -->  
  30.              <security:remember-me key="bookingtest" />  
  31.     </security:http>  
  32.       
  33.     <bean id="jilujiaAuthenticationEntryPoint" class="com.jilujia.framework.security.JilujiaAuthenticationEntryPoint">  
  34.         <property name="loginFormUrl" value="/login" />  
  35.     </bean>  
  36.       
  37.     <bean id="httpSessionRequestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache">  
  38.         <property name="justUseSavedRequestOnGet" value="true" />  
  39.     </bean>  
  40.       
  41.     <!-- 验证普通用户 -->    
  42.     <bean id="loginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">  
  43.         <property name="authenticationManager" ref="authenticationManager"/>  
  44.         <property name="authenticationFailureHandler" ref="failureHandler"/>  
  45.         <property name="authenticationSuccessHandler" ref="successHandler"/>  
  46.         <property name="filterProcessesUrl" value="/loginProcess"/>  
  47.     </bean>  
  48.   
  49.     <bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">  
  50.         <property name="defaultFailureUrl" value="/login?login_error=1" />  
  51.     </bean>  
  52.   
  53.     <bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">  
  54.         <property name="alwaysUseDefaultTargetUrl" value="false"/>  
  55.         <property name="defaultTargetUrl" value="/"/>  
  56.     </bean>  
  57.     <!-- 验证ajax请求-->   
  58.     <bean id="ajaxLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">  
  59.         <property name="authenticationManager" ref="authenticationManager"/>  
  60.         <property name="authenticationFailureHandler" ref="ajaxFailureHandler"/>  
  61.         <property name="authenticationSuccessHandler" ref="ajaxSuccessHandler"/>  
  62.         <property name="filterProcessesUrl" value="/ajaxLoginProcess"/>  
  63.     </bean>  
  64.       
  65.     <bean id="ajaxFailureHandler" class="com.jilujia.framework.security.AjaxAuthenticationFailureHandler">  
  66.     </bean>  
  67.       
  68.     <bean id="ajaxSuccessHandler" class="com.jilujia.framework.security.AjaxAuthenticationSuccessHandler">  
  69.     </bean>  
  70.       
  71.     <security:global-method-security  jsr250-annotations="enabled" secured-annotations="enabled" />   
  72.       
  73.     <security:authentication-manager alias="authenticationManager">  
  74.         <security:authentication-provider user-service-ref="customUserDetailsService">    
  75.             <security:password-encoder ref="passwordEncoder" />  
  76.         </security:authentication-provider>  
  77.     </security:authentication-manager>  
  78.       
  79.     <bean id="customUserDetailsService" class="com.jilujia.framework.security.JilujiaUserDetailsService">   
  80.              <property name="dataSource" ref="dataSource" />     
  81.          </bean>    
  82.   
  83.     <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>  
  84. </beans>  
 

重点有几个:jilujiaAuthenticationEntryPoint,解决问题1, 这里区分ajax请求和非ajax请求的方式是uri中包含不包含ajax字符串,可以按需调整。

 

Java代码  收藏代码
  1. public class JilujiaAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {  
  2.   
  3.     private static final Log logger = LogFactory.getLog(JilujiaAuthenticationEntryPoint.class);  
  4.   
  5.     private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();  
  6.   
  7.     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)  
  8.             throws IOException, ServletException {  
  9.   
  10.         HttpServletRequest httpRequest = (HttpServletRequest) request;  
  11.         HttpServletResponse httpResponse = (HttpServletResponse) response;  
  12.   
  13.         String redirectUrl = null;  
  14.   
  15.         String url = request.getRequestURI();  
  16.   
  17.         if (logger.isDebugEnabled()) {  
  18.             logger.debug("url:" + url);  
  19.         }  
  20.   
  21.         // 非ajax请求  
  22.         if (url.indexOf("ajax") == -1) {  
  23.   
  24.             if (this.isUseForward()) {  
  25.   
  26.                 if (this.isForceHttps() && "http".equals(request.getScheme())) {  
  27.                     // First redirect the current request to HTTPS.  
  28.                     // When that request is received, the forward to the login page will be used.  
  29.                     redirectUrl = buildHttpsRedirectUrlForRequest(httpRequest);  
  30.                 }  
  31.   
  32.                 if (redirectUrl == null) {  
  33.                     String loginForm = determineUrlToUseForThisRequest(httpRequest, httpResponse, authException);  
  34.   
  35.                     if (logger.isDebugEnabled()) {  
  36.                         logger.debug("Server side forward to: " + loginForm);  
  37.                     }  
  38.   
  39.                     RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(loginForm);  
  40.   
  41.                     dispatcher.forward(request, response);  
  42.   
  43.                     return;  
  44.                 }  
  45.             } else {  
  46.                 // redirect to login page. Use https if forceHttps true  
  47.   
  48.                 redirectUrl = buildRedirectUrlToLoginPage(httpRequest, httpResponse, authException);  
  49.   
  50.             }  
  51.   
  52.             redirectStrategy.sendRedirect(httpRequest, httpResponse, redirectUrl);  
  53.         } else {  
  54.             // ajax请求,返回json,替代redirect到login page  
  55.             if (logger.isDebugEnabled()) {  
  56.                 logger.debug("ajax request or post");  
  57.             }  
  58.   
  59.             ObjectMapper objectMapper = new ObjectMapper();  
  60.             response.setHeader("Content-Type""application/json;charset=UTF-8");  
  61.             JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(),  
  62.                     JsonEncoding.UTF8);  
  63.             try {  
  64.                 JsonData jsonData = new JsonData(2null);  
  65.                 objectMapper.writeValue(jsonGenerator, jsonData);  
  66.             } catch (JsonProcessingException ex) {  
  67.                 throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);  
  68.             }  
  69.         }  
  70.     }  
  71.   
  72. }  

 

 第二个问题,注意配置一个新的过滤器专门处理ajax 请求,这个filter是通过filterProcessesUrl=ajaxLoginProcess来区分ajax login动作和普通login动作的。

 

Xml代码  收藏代码
  1.  <!-- ajax登录过滤器 -->  
  2.             <security:custom-filter position="FORM_LOGIN_FILTER" ref="ajaxLoginFilter"/>  
  3.   
  4.             <bean id="ajaxLoginFilter"     class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">  
  5.                   <property name="authenticationManager" ref="authenticationManager"/>  
  6.                   <property name="authenticationFailureHandler" ref="ajaxFailureHandler"/>  
  7.                   <property name="authenticationSuccessHandler" ref="ajaxSuccessHandler"/>  
  8.                   <property name="filterProcessesUrl" value="/ajaxLoginProcess"/>  
  9.              </bean>  
  10.   
  11. 同时对应了两个handler,专门处理ajax登录的成功和失败,都返回json消息。  
  12.             <bean id="ajaxFailureHandler" class="com.jilujia.framework.security.AjaxAuthenticationFailureHandler">  
  13.             </bean>  
  14.   
  15.             <bean id="ajaxSuccessHandler" class="com.jilujia.framework.security.AjaxAuthenticationSuccessHandler">  
  16.             </bean>  
 

 

Java代码  收藏代码
  1. public class AjaxAuthenticationSuccessHandler implements AuthenticationSuccessHandler {  
  2.   
  3.     public AjaxAuthenticationSuccessHandler() {  
  4.     }  
  5.   
  6.     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,  
  7.             Authentication authentication) throws IOException, ServletException {  
  8.   
  9.         ObjectMapper objectMapper = new ObjectMapper();  
  10.         response.setHeader("Content-Type""application/json;charset=UTF-8");  
  11.         JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(),  
  12.                 JsonEncoding.UTF8);  
  13.         try {  
  14.                             //成功为0  
  15.             JsonData jsonData = new JsonData(0null);  
  16.             objectMapper.writeValue(jsonGenerator, jsonData);  
  17.         } catch (JsonProcessingException ex) {  
  18.             throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);  
  19.         }  
  20.     }  
  21. }  
  22.   
  23. public class AjaxAuthenticationFailureHandler implements AuthenticationFailureHandler {  
  24.     protected final Log logger = LogFactory.getLog(getClass());  
  25.   
  26.     public AjaxAuthenticationFailureHandler() {  
  27.     }  
  28.   
  29.     public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,  
  30.             AuthenticationException exception) throws IOException, ServletException {  
  31.         ObjectMapper objectMapper = new ObjectMapper();  
  32.         response.setHeader("Content-Type""application/json;charset=UTF-8");  
  33.         JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(),  
  34.                 JsonEncoding.UTF8);  
  35.         try {  
  36.                             //失败为1  
  37.             JsonData jsonData = new JsonData(1null);  
  38.             objectMapper.writeValue(jsonGenerator, jsonData);  
  39.         } catch (JsonProcessingException ex) {  
  40.             throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);  
  41.         }  
  42.     }  
  43.   
  44. }  
 

 

ajax login page差不多是这样:

Html代码  收藏代码
  1. <div id="inlineLogin" style="width:500px;display: none;">  
  2.     <form id="LoginForm" action="<c:url value="/ajaxLoginProcess" />method="post">  
  3.         <fieldset>  
  4.             <legend>Login Information</legend>  
  5.             <p>  
  6.                 <label for="j_username">User:</label>  
  7.                 <br />  
  8.                 <input type="text" name="j_username" id="j_username" <c:if test="${not empty param.login_error}">value="<%= session.getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY) %>"</c:if> />  
  9.             </p>  
  10.             <p>  
  11.                 <label for="j_password">Password:</label>  
  12.                 <br />  
  13.                 <input type="password" name="j_password" id="j_password" />  
  14.             </p>  
  15.             <p>  
  16.                 <input type="checkbox" name="_spring_security_remember_me" id="remember_me" />  
  17.                 <label for="remember_me">Don't ask for my password for two weeks:</label>  
  18.             </p>  
  19.             <p>  
  20.                 <a href="javascript:loginSubmit()" id='btn_login' class='rndbutton'><span>Login</span></a>  
  21.             </p>  
  22.         </fieldset>  
  23.     </form>  
  24. </div>  

 

Js代码  收藏代码
  1. function loginSubmit(){  
  2.         var form = $('#LoginForm').serialize();  
  3.         $.post('<c:url value="/ajaxLoginProcess" />',form,function(data){  
  4.             if(data.error == 1)  
  5.                 alert(data.messages);  
  6.             else if (data.error == 0){  
  7.                 alert("success")  
  8.             }  
  9.         });  
  10.     }  
 

 

特别注意的是配置了一个

        <!-- 只cache get,避免ajax post 被cache -->
        <security:request-cache ref="httpSessionRequestCache"/>
因为我的环境中所有的post都是ajax,这些都不需要cache。

参考:

http://www.360doc.com/content/12/0712/13/7656232_223767530.shtml

http://blog.csdn.net/zjh527/article/details/6158706

 

 


相关文章推荐

Spring security 3.x 普通login与ajax login笔记

大家都知道,如果Spring Security判断当前用户没有权限访问某个资源时,会根据我们的配置自动跳转到Login页面或者403页面。 但实际上这可能并不是我们想要的:因为对于静态资源来说,浏览...
  • jmppok
  • jmppok
  • 2015年04月02日 16:00
  • 4249

spring security中如何弹出登录模态框(form login与ajax login并存)

问题最近在项目中用到spring security3.1,本来想着只用form login一种方式,从而避免各种麻烦的配置,但是,后来发现,在实际使用过程,有些地方需要利用弹出登录模态框的方式,而这个...

Spring Security 3.1 自定义实例之登陆

Spring Security 3.1 自定义实例之登陆 Spring Security的前身是Acegi,功能强大,配置也比较复杂,我也是新手,先通过动手实现一个登陆验证实例来进入Spring S...

spring security 自定义登陆 - AJAX

除了自定义登陆页面外,我们经常会需要处理ajax登陆  (自定义登陆参考: http://blog.csdn.net/buyaore_wo/article/details/50056353 ) ...

spring security 自定义登陆 - AJAX

除了自定义登陆页面外,我们经常会需要处理ajax登陆  (自定义登陆参考: http://blog.csdn.net/buyaore_wo/article/details/50056353 ) ...

Java 高性能缓存设计思想(Memcache)

# package com.akala.dbcache.core; import java.lang.reflect.Method; import java.net.S...

spring-security 3.0.X, 让ajax login和普通login共存

转自: http://my.oschina.net/jilujia/blog/66795 使用spring security时遇到一个问题,有大量的ajax post是需要登录控制的,但...
  • jmppok
  • jmppok
  • 2015年03月31日 15:00
  • 1110

基于注解的spring-security-login

  • 2017年11月14日 23:13
  • 19KB
  • 下载

在Spring Security4.0 中配置自定义的login页面

最近在研究Spring mvc 4的应用,Security 部分无疑是重要的一块。
  • SamuelQ
  • SamuelQ
  • 2016年05月20日 15:02
  • 2792

Spring Security笔记:自定义Login/Logout Filter、AuthenticationProvider、AuthenticationToken

Spring Security笔记:自定义Login/Logout Filter、AuthenticationProvider、AuthenticationToken 在前面的学习中,配置文件中...
  • jmppok
  • jmppok
  • 2015年04月01日 10:28
  • 3021
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:spring-security 3.0.X, 让ajax login和普通login共存
举报原因:
原因补充:

(最多只允许输入30个字)