涉及到的三个端
oauth2 授权码模式涉及到的全流程,其中涉及到三个端
- 浏览器
- 认证服务 auth服务
- 智声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);
}
}
}