CAS源码追踪系列二:AuthenticationFilter对于请求的处理

Stella981
• 阅读 837

上一篇我们说了在web项目中了和spring整合之后,如何进行对应Filter的初始化,如果你还没看过,请点击 《CAS源码追踪系列一:Filter的初始化》。 本篇我们来看看在初始化完成以后,cas-client是如何处理请求的。

源码地址:https://github.com/apereo/java-cas-client

如何你还不太清楚sso的原理,你可以看看这篇文章《单点登录原理与简单实现》。 当访问系统受保护的资源时,cas的过滤器AuthenticationFilter会对它进行拦截,发现用户没有登录(系统中没有对应的session信息),就会跳转到统一登录页面。否则调用FilterChain中下一个Filter。

来看AuthenticationFilter的

doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,final FilterChain filterChain) if (isRequestUrlExcluded(request)) { logger.debug("Request is ignored."); filterChain.doFilter(request, response); return; } 判断请求是否是不需要被拦截,是,则进行直接调用FilterChain中下一个Filter,否则向下执行 来看看isRequestUrlExcluded方法

private boolean isRequestUrlExcluded(final HttpServletRequest request) { /* *是否有忽略url匹配类, *在AuthenticationFilter的initInternal(final FilterConfig *filterConfig)进行初始化 */ if (this.ignoreUrlPatternMatcherStrategyClass == null) { return false; }

    final StringBuffer urlBuffer = request.getRequestURL();
    if (request.getQueryString() != null) {
        urlBuffer.append("?").append(request.getQueryString());//拼装url
    }
    final String requestUri = urlBuffer.toString();
    /*
    *匹配url是不是不用被拦截,拦截规则需要用户在配置文件配置,
    *在AuthenticationFilter的initInternal(final FilterConfig *filterConfig)加载到ignoreUrlPatternMatcherStrategyClass
    */
    return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
}

final HttpSession session = request.getSession(false);//获取用户session,注意到参数是false,表示session没有的话不新建一个session final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;//如果有session,则从CONST_CAS_ASSERTION属性值获取断言 如果session不存在或者session中CONST_CAS_ASSERTION为空则代表用户还未登录,则需要继续向下执行,否则执行下一个Filter。 final String serviceUrl = constructServiceUrl(request, response);//解析请求地址 该方法最终调用

CommonUtils.constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response, final String service, final String serverNames, final String serviceParameterName, final String artifactParameterName, final boolean encode); @param service: 服务地址或者说是你要请求的地址,该方法更乐意你提供这个参数(可在配置文件配置) @param serverName:服务名,如http://localhost:8080

if (CommonUtils.isNotBlank(service)) { return encode ? response.encodeURL(service) : service; } 代码一开始先对server参数进行校验,如何不为空,直接返回。这也就是为什么为什么期望你配置这个参数,逻辑简单啊。 如果不为空,则需要对请求的url进行解析。

final String serverName = findMatchingServerName(request, serverNames); final URIBuilder originalRequestUrl = new URIBuilder(request.getRequestURL().toString(), encode); originalRequestUrl.setParameters(request.getQueryString());

    final URIBuilder builder;
    if (!serverName.startsWith("https://") && !serverName.startsWith("http://")) {
        String scheme = request.isSecure() ? "https://" : "http://";
        builder = new URIBuilder(scheme + serverName, encode);
    } else {
        builder = new URIBuilder(serverName, encode);
    }

    if (builder.getPort() == -1 && !requestIsOnStandardPort(request)) {
        builder.setPort(request.getServerPort());
    }

    builder.setEncodedPath(builder.getEncodedPath() + request.getRequestURI());

根据url获取请求参数(request.getQueryString())时,会判断有没有携带ticket参数且必须在第一个位置(location==0),如果是就直接返回之前拼装的url,否则继续拼装参数 。

final List serviceParameterNames = Arrays.asList(serviceParameterName.split(",")); if (!serviceParameterNames.isEmpty() && !originalRequestUrl.getQueryParams().isEmpty()) { for (final URIBuilder.BasicNameValuePair pair : originalRequestUrl.getQueryParams()) { String name = pair.getName(); if (!name.equals(artifactParameterName) && !serviceParameterNames.contains(name)) { if (name.contains("&") || name.contains("=") ){ URIBuilder encodedParamBuilder = new URIBuilder(); encodedParamBuilder.setParameters(name); for (final URIBuilder.BasicNameValuePair pair2 :encodedParamBuilder.getQueryParams()){ String name2 = pair2.getName(); if (!name2.equals(artifactParameterName) && !serviceParameterNames.contains(name2)) { builder.addParameter(name2, pair2.getValue()); } } } else { builder.addParameter(name, pair.getValue()); } } } 主要就是过滤掉名为“ticket”的参数。 再回到AuthenticationFilter

final String ticket = retrieveTicketFromRequest(request);//获取请求中的ticket 然后判断如果有ticket而且设置了网关,就直接调用下一个Filter,否则继续向下执行。

final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway); 根据已有的数据构造一个重定向url,也就是对于请求认证失败的时候跳转的地址,类似于https://localhost:8443/cas/login?service=https%3A%2F%2Flocalhost%3A8443%2Ftest%3Ftest%3D12456%26sss%3D111。“?”前面部分为认证中心登录页面,后面则为登录成功之后要跳转的地址。

最后一步就是执行重定向。

总结

这一片我们简单分析了cas-client如何处理请求,对于认证成功的继续执行下一个Filter,失败的则跳转到登录页面。下一篇我们会讲cas-server端是如何处理登录的。

平时的学习过程记录一下,没有那么高深,希望能帮到大家,与君共同进步。我是敲代码的小鲁班,喜欢的话给个推荐,点赞,关注吧。 CAS源码追踪系列二:AuthenticationFilter对于请求的处理

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这