Spring Security 認證成功後跳轉錯誤碼404
- 描述問題
瀏覽器中輸入http://localhost:8080/test.html,認證服務跳轉到login.html,輸入正確的賬號密碼後,跳轉過去返回404。
- 分析問題
pom主要資訊
spring boot version 2.0.4.RELEASE
spring security 、MVC version 2.0.4.RELEASE
仔細看了最後跳轉的路徑,是根路徑“\”,和初衷test.html天壤之別。
@Component("mSuccessHandler") public class CustomAuthenticationSuccesstHandler extends SimpleUrlAuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request , HttpServletResponse response , Authentication authentication) throws IOException, ServletException { super.onAuthenticationSuccess(request, response, authentication); } } }
檢視原始碼super.OnAuthenticationSuccess(request,response,authentication);
public class SimpleUrlAuthenticationSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements AuthenticationSuccessHandler { public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { this.handle(request, response, authentication); this.clearAuthenticationAttributes(request); } }
繼續this.handle(request,response,authentication);
public abstract class AbstractAuthenticationTargetUrlRequestHandler { protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { String targetUrl = this.determineTargetUrl(request, response); if (response.isCommitted()) { this.logger.debug("Response has already been committed. Unable to redirect to " + targetUrl); } else { this.redirectStrategy.sendRedirect(request, response, targetUrl); } } protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) { if (this.isAlwaysUseDefaultTargetUrl()) { return this.defaultTargetUrl; } else { String targetUrl = null; if (this.targetUrlParameter != null) { targetUrl = request.getParameter(this.targetUrlParameter); if (StringUtils.hasText(targetUrl)) { this.logger.debug("Found targetUrlParameter in request: " + targetUrl); return targetUrl; } } if (this.useReferer && !StringUtils.hasLength(targetUrl)) { targetUrl = request.getHeader("Referer"); this.logger.debug("Using Referer header: " + targetUrl); } if (!StringUtils.hasText(targetUrl)) { targetUrl = this.defaultTargetUrl; this.logger.debug("Using default Url: " + targetUrl); } return targetUrl; } } }
繼續 this.determineTargetUrl(request, response);
target有三種被修改的可能方式:
1.targetUrlParameter不等於空
targetUrlParameter這是個成員屬性,可以通過public void setTargetUrlParameter(String targetUrlParameter) {......}設定,而後targetUrl = request.getParameter(this.targetUrlParameter);
那麼如何處理才能得到這個tergetUri呢?requestParameter該方法就是根據http上傳的引數,而後獲取其值。這裡我本想通過request設定其值,但是request不支援setParameter這個方法,個人猜想也是為了保護該次請求唯一性吧。
假設可以通過某些方式,成功添加了請求引數,除非約束了請求跳轉的引數名字,否則
targetUrl = request.getParameter(this.targetUrlParameter); 這個this.targetUriParameter也是個棘手的事情。
2. targetUrl = request.getHeader("Referer");通過header.Refer
同前者一樣,request不支援setHeader一些api。
3.targetUrl = this.defaultTargetUrl;
前兩種情況都為空的時候,只能使用預設的Uri,也就是跳轉後報404的結果的路徑“\”。
- 解決問題
package com.fosun.springsecurity.authentication;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fosun.springsecurity.properties.LoginType;
import com.fosun.springsecurity.properties.SecurityProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: Christ
* @date: 2018/8/16 11:18
* @desc:
*/
@Component("mAuthSuccessHandler")
public class CustomerAuthenticationSuccessRedirectHandler extends SimpleUrlAuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(CustomerAuthenticationSuccessRedirectHandler.class);
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
private RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess(HttpServletRequest request
, HttpServletResponse response
, Authentication authentication)
throws IOException, ServletException {
logger.info("登入成功");
if(securityProperties.getBrowser().getLoginType() == LoginType.JSON){
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(objectMapper.writeValueAsString(authentication));
}else{
SavedRequest savedRequest = requestCache.getRequest(request,response);
String targetUrl = savedRequest.getRedirectUrl();
getRedirectStrategy().sendRedirect(request,response,targetUrl);
clearAuthenticationAttributes(request);
}
}
}
- 結語
如果哪位同行有更好的建議和方法,還望不吝賜教。