Spring Security Oauth2 認證流程時序圖


涉及到的三個端

oauth2 授權碼模式涉及到的全流程,其中涉及到三個端

  1. 瀏覽器
  2. 認證服務 auth服務
  3. 智聲gateway

示例中所有url

  1.http://localhost:8089/api/oauth?callbackurl=https://www.baidu.com

  2.http://10.0.0.114:10300/auth/oauth/authorize?response_type=code&client_id=LingOSClient&redirect_uri=http://10.0.0.114:8089/api/callback?callbackurl=https://www.baidu.com&state=7965388762f3ef7446badd593c1e34f9&scope=all

  4.http://10.0.0.114:10300/auth/index.html?callbackurl=http://10.0.0.114:10300/auth/oauth/authorize?response_type=code&client_id=LingOSClient&redirect_uri=http://10.0.0.114:8089/api/callback?callbackurl=https://www.baidu.com&state=1a0852e75673df27ac67e94fb65d8177&scope=all

  5.http://10.0.0.114:10300/auth/process

  7.http://10.0.0.114:10300/auth/oauth/authorize?response_type=code&client_id=LingOSClient&redirect_uri=http://10.0.0.114:8089/api/callback?
callbackurl=https://www.baidu.com&state=92cfdd70e7847e8b468c285313a18929&scope=all

  8.http://10.0.0.114:8089/api/callback?callbackurl=https://www.baidu.com&code=XFGBFr&state=92cfdd70e7847e8b468c285313a18929

callbackUrl參數說明:

1.遇到的問題:

第一個子產品跳轉到登錄頁面會產生一個auth域下cookie,第二個子產品在跳轉到登錄頁面的時候回攜帶第一個子產品的cookie,從而把第一個子產品的
savedRequest(redis中 sessionAttr:SPRING_SECURITY_SAVED_REQUEST)覆蓋掉,導致第一個子產品登錄成功以后跳轉回去的地址錯誤。

  DefaultRedirectStrategy#sendRedirect(HttpServletRequest, HttpServletResponse, String)
  //跳轉到index.html頁面,eg: http://auth.aicloud-test.com/auth/index.html

2.解決辦法:

跳轉到index.html頁面時后面綴上跳轉回去的參數 callbackurl,eg: http://auth.aicloud-test.com/auth/index.html?callbackurl=xxxx

  @see DefaultRedirectStrategy#sendRedirect(HttpServletRequest, HttpServletResponse, String) 被下面的替換掉
  @see CustomLoginUrlAuthenticationEntryPoint#determineUrlToUseForThisRequest(HttpServletRequest, HttpServletResponse, AuthenticationException) 后續請求在
  @see CustomLoginSuccessHandler 中獲取到callbackurl=xxxx參數,直接跳轉回去
@Slf4j
public class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
    /**
     * @param loginFormUrl URL where the login page can be found. Should either be
     *                     relative to the web-app context path (include a leading {@code /}) or an absolute
     *                     URL.
     */
    public CustomLoginUrlAuthenticationEntryPoint(String loginFormUrl) {
        super(loginFormUrl);
    }
	
	/**
     * 拼接callbackurl參數到loginPage后
     *
     * @return 重定向到登錄頁面
     */
    @SneakyThrows
    @Override
    protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {
        String savedRequestUrl = request.getRequestURL() + "?" + request.getQueryString();
        //這里編碼不能使用UrlEncode,會導致參數丟失
        String base64EncodeSavedRequestUrl = Base64.encode(savedRequestUrl, StandardCharsets.UTF_8);
        String redirectUrl = super.getLoginFormUrl() + "?callbackurl=" + base64EncodeSavedRequestUrl;

        log.info("savedRequestUrl:【{}】,redirectUrl:【{}】", savedRequestUrl, super.getLoginFormUrl() + "?callbackurl=" + savedRequestUrl);
        return redirectUrl;
    }
}



@Slf4j
@Component
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private static ObjectMapper objectMapper = new ObjectMapper();
    private RequestCache requestCache = new HttpSessionRequestCache();

	@Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {

        // 判斷是不是ajax請求
        String ajax = Optional.ofNullable(request
                .getParameterMap().get("_ajax")).flatMap(t -> Arrays.stream(t).findFirst()
        ).orElse(StrUtil.EMPTY);

        /**
         * {@link CustomLoginUrlAuthenticationEntryPoint}獲取認證時的url,模仿 {@link DefaultSavedRequest}行為
         */
        String base64EncodeSavedRequestUrl = Optional.ofNullable(request
                .getParameterMap().get("callbackurl")).flatMap(t -> Arrays.stream(t).findFirst()
        ).orElse(StrUtil.EMPTY);

        String savedRequestUrl = Base64.decodeStr(base64EncodeSavedRequestUrl);
		SavedRequest savedRequest = requestCache.getRequest(request, response);

        String targetUrlParameter = getTargetUrlParameter();
		if (isAlwaysUseDefaultTargetUrl()
                || (targetUrlParameter != null && StringUtils.hasText(request
                .getParameter(targetUrlParameter)))) {
            requestCache.removeRequest(request, response);
            super.onAuthenticationSuccess(request, response, authentication);

            return;
        }
		
        clearAuthenticationAttributes(request);

		
        if (Boolean.parseBoolean(ajax)) {
            HashMap<Object, Object> returnData = new HashMap<>();
            returnData.put("url", savedRequestUrl);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(Result.ok(returnData)));
        } else {
            getRedirectStrategy().sendRedirect(request, response, savedRequestUrl);
        }
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM