记录一次前后端分离完成cas单点登录的过程

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。

这几天研究了一下前后端分离的模式下如何进行cas单点登录认证,大致流程主要参考了这篇文章->链接。根据自身的情况进行了一些调整。

首先cas认认证一般都是采用第三方的厂商提供的服务完成的,有些版本比较老的话说明文档很可能就是一体式的服务,不会有前后端分离的操作流程。在前后端分离的模式下首要解决的就是跳转的问题,正常的认证流程大体是:

前端发起请求->后端cas的过滤器处理请求->认证通过直接放行,不通过进行下一步->跳转到cas服务的认证页面进行认证->认证完后重定向会原来的页面

很大一部分的问题就是出现在认证完成后重定向会原来页面,因为ajax请求无法302跳转,所以最后一步就回不去了。解决的办法就是让后端帮助前端完成最后一步的跳转。

首先假设前端地址为:http://172.27.113.88

后端地址为:http://172.27.113.66

cas认证服务地址:http://172.27.113.77/cas

后端采用的是springboot框架,配置cas的过滤器是通过@Configuration配置,示例如下:

@Bean
public FilterRegistrationBean authenticationFilter() {
    FilterRegistrationBean bean = new FilterRegistrationBean<>(new AuthenticationFilter());
    bean.setName("CASAuthenticationFilter");
    bean.addUrlPatterns("/*");
    bean.setOrder(1);
    Map map=new HashMap();
    map.put("serverName","后端地址");
    map.put("casServerLoginUrl","cas认证服务地址");
    bean.setInitParameters(map);
    return bean;
}
复制代码

首先要修改的是前端的认证逻辑,前端先判断用户是否登录(在路由前面加过滤器或者拦截器判断cookie里是否有用户认证的jsessionid或者自定义的判断逻辑都可),没有登陆的话就访问一个固定的后台接口,在这个接口里后台完成接下来的一系列操作。我这里以login接口为例:

@RequestMapping("/login")
public Map loginUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
    AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    System.out.println("principal = " + principal.getAttributes());
    String url = "前台跳转地址";
    Cookie[] cookies = request.getCookies();
    String s = cookies[0];
    for (Cookie c : cookies) {
        System.out.println(c.getName() + "--->" + c.getValue());
    }
    response.sendRedirect(url + "?jsessionid=" + s);
    ...
    ...
    }
复制代码

当前台访问这个接口到后台时首先起作用的是几个cas的过滤器,过滤器会跳转到他对应的认证页面进行认证,认证完后因为在过滤器里设置的serverName是后端地址,所以又会回到这个接口继续往下走,在接口里就可以那到认证完后在principal里的一些用户信息用于一些业务需求,不需要的话也可以不拿,这里最主要的是通过response.sendRedirect(url + "?jsessionid=" + s)这个操作来帮助前端重定向到原来的页面,同时还要把jsessionid返回给前端让前端放到cookie里,后续的访问只要cookie里带有这个认证信息就可以通过cas的过滤器。需要注意的是这里的jsessionid是根据实际情况来的,我这里的cas认证是可以通过这个jsessionid来验证你是否登陆的,也有可能需要tokenid等一些其他的令牌之类的来进行验证,这就跟具体厂商提供的cas认证有关了。还需要注意的是跳转的地址得是绝对地址,不能单写一个ip地址,这样是跳不过去的,要带上http或者https。

跳转的cas认证url如下:

image.png

可以看到service后面跟着的就是认证完成后要跳回去的地址。

最后的总结如下:

  1. 先对接后台服务。把后台程序单独拿出来,看做是一个前后端不分离的应用,按照前后端不分离的方式对接,浏览器地址栏直接请求后台接口(如订单列表接口),是否对接成功也很容易验证,认证中心登录后,该后台地址的接口在浏览器界面返回了订单列表的数据即认为认证成功了,也就是后端代码对接成功了CAS。这样的好处是可以快速先把CAS集成进来,如果直接在前后端分离的体系下对接,因为本身有前后端分离的问题在里面,很难确认CAS集成是否有问题。
  2. 接入前端页面。即通过前端页面再来尝试调用该后台接口,启动前端程序,比如点击订单列表页面的查询按钮调用该订单列表接口。后台CAS filter拦截到前端发出的请求,认证校验未通过,返回302重定向的状态码,浏览器拿到302尝试跳转,但是跳转失败了。原因是该请求是前端代码发起的ajax请求,ajax请求无法302跳转,前端代码也无法捕捉跳转,这种情况不用考虑在前端代码中实现跳转了。
  3. 考虑后端处理。前后端不分离的应用中页面跳转可以直接在后端java代码中用response.sendRedirect()直接跳转到指定地址,这种方式在以前的前后端不分离的JSP项目中没问题,但是前后端分离的项目不一定行,可以尝试上文中写的方法。查看CAS源码,发现CAS认证不通过,跳转到登录页最终也是response.sendRedirect()来实现,所以可以考虑能否拦截或者重写覆盖CAS跳转相关的代码,让这里的处理不走默认的跳转逻辑,自定义处理方式,返回401状态码给调用方(也就是前端代码),并且带上要跳转的链接,前端可以捕获401状态码的返回结果,获取要跳转的链接后跳转过去,这样也是一种可行的办法。
  4. 检查是否有新问题引入。实践证明上述思路是可行的,CAS本身的代码设计也非常优雅,提供给了我们覆盖相关逻辑的方式,具体方式请看后面的实现。重写CAS认证失败页面跳转的相关代码,前后端分离应用就可以正常对接CAS了,可能有一些小的细节问题处理,但是没有新的流程阻塞问题引入,如果有新问题,比如跨域,针对性解决即可。

おすすめ

転載: juejin.im/post/7068922646448046094