CAS5.3-Nginx转发OAuth2.0请求导致验证失败的问题分析 | 字痕随行

先说说环境吧:

  • CAS在Nginx后面,所有的请求经由Nginx转发。
  • CAS开启了OAuth2.0模块

其它的都是正常配置了,但是当OAuth2.0请求验证时,总会跳转到一个内网地址,就很纳闷为什么。

最后,只能通过分析源码来寻找原因了。

通过浏览器的开发助手,我们知道卡住的位置在callbackAuthorize这个地址,它的302重定向会到一个内网地址,响应头如下:

cache-control: no-cache, no-store, max-age=0, must-revalidate
content-language: zh-CN
content-length: 0
date: Thu, 09 Mar 2023 05:41:13 GMT
expires: 0
location: http://192.168.1.1:39999/oauth2.0/authorize?client_id=cliendId&redirect_uri=callback地址&response_type=code&state=uuid
pragma: no-cache
server: nginx/1.x.x
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block

按道理都有redirect地址,怎么都不会跳转到一个内网的地址,尤其只是域名更换了,后面的地址链接还都是正确的。

直接看callbackAuthorize这个地址的处理逻辑就好了,为什么会response这么一个location出来?下面是该controller的代码:

@GetMapping(path = OAuth20Constants.BASE_OAUTH20_URL + '/' + OAuth20Constants.CALLBACK_AUTHORIZE_URL)
public ModelAndView handleRequest(final HttpServletRequest request, final HttpServletResponse response) {
    final J2EContext context = new J2EContext(request, response, this.oauthConfig.getSessionStore());
    final DefaultCallbackLogic callback = new DefaultCallbackLogic();
    //直接看这个方法,这方法决定了response的header
    callback.perform(context, oauthConfig, J2ENopHttpActionAdapter.INSTANCE,
        null, Boolean.TRUE, Boolean.FALSE,
        Boolean.FALSE, Authenticators.CAS_OAUTH_CLIENT);
    final String url = StringUtils.remove(response.getHeader("Location"), "redirect:");
    final ProfileManager manager = Pac4jUtils.getPac4jProfileManager(request, response);
    return oAuth20CallbackAuthorizeViewResolver.resolve(context, manager, url);
}

然后就是Pac4j的内部代码了:

protected HttpAction redirectToOriginallyRequestedUrl(final C context, final String defaultUrl) {
    final String requestedUrl = (String) context.getSessionStore().get(context, Pac4jConstants.REQUESTED_URL);
    String redirectUrl = defaultUrl;
    if (isNotBlank(requestedUrl)) {
        context.getSessionStore().set(context, Pac4jConstants.REQUESTED_URL, null);
        redirectUrl = requestedUrl;
    }
    logger.debug("redirectUrl: {}", redirectUrl);
    return HttpAction.redirect(context, redirectUrl);
}

注意上面代码中的requestedUrl,是从sessionStore里面取出的。那下一步就很明确了,这url是怎么存进去的。

找这个url的思路如下:

  • 身份验证肯定有个验证的方法,所以这段验证逻辑在哪,会导致它要转到login路径。
  • Pac4j是个登录验证的封装工具。

所以,就是想一想,就是要找登录验证的地方,就找到了下面这段代码:

@ConditionalOnMissingBean(name = "requiresAuthenticationAuthorizeInterceptor")
@Bean
public SecurityInterceptor requiresAuthenticationAuthorizeInterceptor() {
    return new SecurityInterceptor(oauthSecConfig.getIfAvailable(), Authenticators.CAS_OAUTH_CLIENT);
}

继续找到preHandle,就会找到RequestUrl是怎么保存进来的:

protected void saveRequestedUrl(final C context, final List<Client> currentClients) {
    if (ajaxRequestResolver == null || !ajaxRequestResolver.isAjax(context)) {
        //就这里了,怎么获取RequestURL的
        final String requestedUrl = context.getFullRequestURL();
        logger.debug("requestedUrl: {}", requestedUrl);
        context.getSessionStore().set(context, Pac4jConstants.REQUESTED_URL, requestedUrl);
    }
}

然后,就看到了request.getRequestURL()。

当时我就给跪了,要是Nginx转发的,那不就是个内网地址,真实的地址都放到header了。

原始代码是真的不想改了,只能想想别的变通方法了,不行就把Nginx去了吧。

以上,如果有错误,欢迎探讨和指正。

image

觉的不错?可以关注我的公众号↑↑↑