1. 程式人生 > >Spring Security 認證成功後跳轉錯誤碼404

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);
        }
    }
}
  • 結語

如果哪位同行有更好的建議和方法,還望不吝賜教。