Spring Security 认证成功后跳转错误码404

  • 描述问题

浏览器中输入http://localhost:8080/test.html,认证服务跳转到login.html,输入正确的账号密码后,跳转过去返回404。

Spring Security 认证成功后跳转错误码404_第1张图片

 

  • 分析问题
     
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);
        }
    }
}
  • 结语

如果哪位同行有更好的建议和方法,还望不吝赐教。

你可能感兴趣的:(spring,security)