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