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

使用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

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
org.springframework.security.authentication.InternalAuthenticationServiceException: null at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:123) ~[spring-security-core-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144) ~[spring-security-core-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:95) ~[spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) [spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) [spring-security-web-5.3.4.RELEASE.jar:5.3.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.9.RELEASE.jar:5.2.9.
最新发布
07-20

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值