MaxKey 单点登录认证系统——登录验证流程分析

客户端依赖包

<dependency><groupId>net.unicon.cas</groupId><artifactId>cas-client-autoconfig-support</artifactId><version>2.3.0-GA</version>
</dependency>

未登录时

  1. 浏览器向客户端发送请求 http://localhost:8989/test1/index

  2. 客户端: AbstractTicketValidationFilter 过滤器拦截

    public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {if (this.preFilter(servletRequest, servletResponse, filterChain)) {HttpServletRequest request = (HttpServletRequest)servletRequest;HttpServletResponse response = (HttpServletResponse)servletResponse;String ticket = this.retrieveTicketFromRequest(request);//校验请求中是否有ticketif (CommonUtils.isNotBlank(ticket)) {this.logger.debug("Attempting to validate ticket: {}", ticket);try {//校验ticket是否正确Assertion assertion = this.ticketValidator.validate(ticket, this.constructServiceUrl(request, response));this.logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());//校验成功设置 _const_cas_assertion_属性request.setAttribute("_const_cas_assertion_", assertion);if (this.useSession) {request.getSession().setAttribute("_const_cas_assertion_", assertion);}this.onSuccessfulValidation(request, response, assertion);if (this.redirectAfterValidation) {//重定向请求this.logger.debug("Redirecting after successful ticket validation.");response.sendRedirect(this.constructServiceUrl(request, response));return;}} catch (TicketValidationException var8) {//校验失败抛出异常this.logger.debug(var8.getMessage(), var8);this.onFailedValidation(request, response);if (this.exceptionOnValidationFailure) {throw new ServletException(var8);}response.sendError(403, var8.getMessage());return;}}//没有ticket直接放行filterChain.doFilter(request, response);}}
    
  3. 客户端:重定向之后的请求是没有 ticket的,所以经过上述的过滤器会直接放行,放行后来到下一个过滤器 AuthenticationFilter

    public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest)servletRequest;HttpServletResponse response = (HttpServletResponse)servletResponse;//判断请求需不需要拦截if (this.isRequestUrlExcluded(request)) {this.logger.debug("Request is ignored.");filterChain.doFilter(request, response);} else {HttpSession session = request.getSession(false);Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;//获取请求中的 _const_cas_assertion_值if (assertion != null) {//如果以上过滤器检验通过此时是有值得,直接放行请求filterChain.doFilter(request, response);} else {String serviceUrl = this.constructServiceUrl(request, response);String ticket = this.retrieveTicketFromRequest(request);boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);//无 _const_cas_assertion_值,再次判断有无 ticketif (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {//也没有ticket重定向到配置文件配置的服务器this.logger.debug("no ticket and no assertion found");String modifiedServiceUrl;if (this.gateway) {this.logger.debug("setting gateway attribute in session");modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);} else {modifiedServiceUrl = serviceUrl;}this.logger.debug("Constructed service url: {}", modifiedServiceUrl);//获取重定向请求String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);this.logger.debug("redirecting to \"{}\"", urlToRedirectTo);//重定向发送this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);} else {filterChain.doFilter(request, response);}}}}
    
  4. 服务器端:接收到重定向请求后被拦截器 SingleSignOnlnterceptor拦截

     @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {logger.trace("Single Sign On Interceptor");AuthorizationUtils.authenticateWithCookie(request,authTokenService,sessionManager);//判断请求是否有current_authentication值if(AuthorizationUtils.isNotAuthenticated()) {//没有则重定向 `/sign/static/index.html/#/passport/login?redirect_uri=http://localhost:9527/sign/authz/cas/login?service=http%3A%2F%2Flocalhost%3A8989%2Ftest1%2Findex`String loginUrl = applicationConfig.getFrontendUri() + "/index.html/#/passport/login?redirect_uri=%s";String redirect_uri = UrlUtils.buildFullRequestUrl(request);String base64RequestUrl = Base64Utils.base64UrlEncode(redirect_uri.getBytes());logger.debug("No Authentication ... Redirect to /passport/login , redirect_uri {} , base64 {}",redirect_uri ,base64RequestUrl);response.sendRedirect(String.format(loginUrl,base64RequestUrl));return false;}//...}
    

    注意:applicationConfig.getFrontendUri()获取的是配置文件的 maxkey.server.frontend.uri,记得配置好

    在这里插入图片描述

  5. 重定向登录界面后输入账号密码登录,登录成功成功后返回jwt信息

  6. 前端处理响应信息,设置token和ticket等信息

    auth(authJwt: any) {let user: User = {name: `${authJwt.displayName}(${authJwt.username})`,displayName: authJwt.displayName,username: authJwt.username,userId: authJwt.id,avatar: './assets/img/avatar.svg',email: authJwt.email,passwordSetType: authJwt.passwordSetType};//tokenthis.cookieService.set(CONSTS.CONGRESS, authJwt.token, { path: '/' });//ticketthis.cookieService.set(CONSTS.ONLINE_TICKET, authJwt.ticket, { domain: this.getSubHostName(), path: '/' });if (authJwt.remeberMe) {localStorage.setItem(CONSTS.REMEMBER, authJwt.remeberMe);}this.settingsService.setUser(user);this.tokenService.set(authJwt);this.tokenService.get()?.expired;}
    
  7. 如果地址后面有拼接 redirect_uri,则会重定向到拼接的地址,如上述的 http://localhost:9527/sign/authz/cas/login?service=http%3A%2F%2Flocalhost%3A8989%2Ftest1%2Findex

    navigate(authJwt: any) {// 重新获取 StartupService 内容,我们始终认为应用信息一般都会受当前用户授权范围而影响this.startupService.load().subscribe(() => {let url = this.tokenService.referrer!.url || '/';if (url.includes('/passport')) {url = '/';}if (localStorage.getItem(CONSTS.REDIRECT_URI) != null) {this.redirect_uri = `${localStorage.getItem(CONSTS.REDIRECT_URI)}`;localStorage.removeItem(CONSTS.REDIRECT_URI);}if (this.redirect_uri != '') {console.log(`redirect_uri ${this.redirect_uri}`);//重定向location.href = this.redirect_uri;}this.router.navigateByUrl(url);});}
    
  8. 服务端:服务器接受重定向后的地址请求,并由 SingleSignOnInterceptor再次拦截,相比未登录的,此时的请求携带了一些登录后设置的jwt信息,就可以设置 current_authentication

    @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {logger.trace("Single Sign On Interceptor");//根据请求携带的信息设置 current_authenticationAuthorizationUtils.authenticateWithCookie(request,authTokenService,sessionManager);if(AuthorizationUtils.isNotAuthenticated()) {//...}//判断请求是否有 current_authentication值if(AuthorizationUtils.isAuthenticated()){logger.debug("preHandle {}",request.getRequestURI());Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);if(app == null) {String requestURI = request.getRequestURI();if(requestURI.contains("/authz/cas/login")) {//for CAS service//获取`service`后面的值,即 http://localhost:8989/test1/index,并根据此service查询配置的应用信息app = casDetailsService.getAppDetails(request.getParameter(CasConstants.PARAMETER.SERVICE), true);}//...}if(app == null) {logger.debug("preHandle app is not exist . ");return true;}SignPrincipal principal = AuthorizationUtils.getPrincipal();if(principal != null && app !=null) {//判断是否有权限访问应用,有则放行if(principal.getGrantedAuthorityApps().contains(new SimpleGrantedAuthority(app.getId()))) {logger.trace("preHandle have authority access {}" , app);return true;}}logger.debug("preHandle not have authority access {}" , app);response.sendRedirect(request.getContextPath()+"/authz/refused");return false;}return true;}
    
  9. 放行之后,再经过一系列操作跳转 http://localhost:8989/test1/index界面

成功登录后

  1. 成功登录后再次请求 http://localhost:8989/test1/index地址

  2. 此时请求中含有ticket,而客户端校验ticket没问题后会设置 _const_cas_assertion_属性

    public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {if (this.preFilter(servletRequest, servletResponse, filterChain)) {HttpServletRequest request = (HttpServletRequest)servletRequest;HttpServletResponse response = (HttpServletResponse)servletResponse;String ticket = this.retrieveTicketFromRequest(request);if (CommonUtils.isNotBlank(ticket)) {this.logger.debug("Attempting to validate ticket: {}", ticket);try {Assertion assertion = this.ticketValidator.validate(ticket, this.constructServiceUrl(request, response));this.logger.debug("Successfully authenticated user: {}", assertion.getPrincipal().getName());//在服务器 session中设置 _const_cas_assertion_属性request.setAttribute("_const_cas_assertion_", assertion);if (this.useSession) {request.getSession().setAttribute("_const_cas_assertion_", assertion);}this.onSuccessfulValidation(request, response, assertion);if (this.redirectAfterValidation) {this.logger.debug("Redirecting after successful ticket validation.");response.sendRedirect(this.constructServiceUrl(request, response));return;}} catch (TicketValidationException var8) {this.logger.debug(var8.getMessage(), var8);this.onFailedValidation(request, response);if (this.exceptionOnValidationFailure) {throw new ServletException(var8);}response.sendError(403, var8.getMessage());return;}}filterChain.doFilter(request, response);}}
    
  3. 后续请求直接判断请求中是否有 const_cas_assertion 属性,有就说明登录过了,请求放行

    public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest)servletRequest;HttpServletResponse response = (HttpServletResponse)servletResponse;if (this.isRequestUrlExcluded(request)) {this.logger.debug("Request is ignored.");filterChain.doFilter(request, response);} else {HttpSession session = request.getSession(false);Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;if (assertion != null) {//不为空请求放行filterChain.doFilter(request, response);} //...}}
    
  4. 此时登录别的应用地址,由于服务器session中已经设置 _const_cas_assertion_属性值,所以也可以直接校验通过

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/251089.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高级Java开发工程师岗位的基本职责(合集)

高级Java开发工程师岗位的基本职责1 职责&#xff1a; 1、负责区块链产品的研发&#xff0c;独立或与团队合作&#xff0c;按时保质完成软件开发项目; 2、参与产品系统设计、概要设计工作&#xff0c;核心功能的代码编写; 3、独立解决和指导其他同事处理开发中遇到的难点问题; …

Qt扩展-muParser数学公式解析

muParser数学公式解析 一、概述1. 针对速度进行了优化2. 支持的运算符3. 支持的函数4. 用户定义的常量5. 用户定义的变量6. 自定义值识别回调7. 其他功能 二、内置函数三、内置二元运算符四、三元运算符五、内置常量六、源码引入1. 源码文件2. 编译器开关1. MUP_BASETYPE2.MUP_…

Unity DOTS中的baking(三)过滤baking的输出

Unity DOTS中的baking&#xff08;三&#xff09;过滤baking的输出 默认情况下&#xff0c;在conversation world&#xff08;baker和baking system运行的环境&#xff09;下产生的所有entities和components&#xff0c;都会作为baking环节的输出。在baking结束时&#xff0c;U…

重写Sylar基于协程的服务器(5、IO协程调度模块的设计)

重写Sylar基于协程的服务器&#xff08;5、IO协程调度模块的设计&#xff09; 重写Sylar基于协程的服务器系列&#xff1a; 重写Sylar基于协程的服务器&#xff08;0、搭建开发环境以及项目框架 || 下载编译简化版Sylar&#xff09; 重写Sylar基于协程的服务器&#xff08;1、…

STM32--USART串口(2)串口外设

一、USART简介 可配置数据位&#xff1a;不需要校验就是8位&#xff0c;需要校验就选9位&#xff1b; 停止位&#xff1a;决定了帧的间隔; STM32F103C8T6USART&#xff1a;USART1挂载在APB2总线上&#xff0c;USART2和USART3挂载在APB1总线上&#xff1b; 二、USART框图 TXE…

STM32外部中断(红外传感器与旋转编码器计数案例)

文章目录 一、介绍部分简介中断系统中断执行流程STM32中断NVIC基本结构NVIC优先级分组外部中断外部中断简介外部中断基本结构外部中断的流程AFIOEXTI框图 相关外设介绍旋转编码器介绍硬件电路对射式红外传感器 二、代码实现对射式红外传感器计次连接电路封装红外传感器与中断函…

Cambalache in Ubuntu

文章目录 前言apt install flatpak这很ok快捷方式后记 前言 gtkmm4相比gtkmm3有很多改革, 代码也干净了许多, 但在windows上开发 有ui设计器那自然方便很多, 但glade又不支持gtkmm4, windows上装Cambalache很是困难. 各种问题都找不到答案.于是 我用VMware虚拟机Ubuntu20.xx安…

探索智慧文旅:科技如何提升游客体验

随着科技的迅猛发展&#xff0c;智慧文旅已成为旅游业的重要发展方向。通过运用先进的信息技术&#xff0c;智慧文旅不仅改变了传统旅游业的运营模式&#xff0c;更在提升游客体验方面取得了显著成效。本文将深入探讨科技如何助力智慧文旅提升游客体验。 一、智慧文旅的兴起与…

React详解

前言 React是一个用于构建用户界面的javaScript库&#xff0c;起源于facebook的内部项目&#xff0c;在13年f进行开源 17版本官网&#xff1a;React – A JavaScript library for building user interfaces 18版本官网&#xff1a;React 官方中文文档 特点&#xff1a; 声…

项目中使用sonar扫码代码

1.在maven的settings.xml配置 org.sonarsource.scanner.maven <profiles> <profile><id>sonar</id><activation><activeByDefault>true</activeByDefault></activation><properties><!-- Optional URL to server. D…

ubuntu20配置mysql8

首先更新软件包索引运行 sudo apt update命令。然后运行 sudo apt install mysql-server安装MySQL服务器。 安装完成后&#xff0c;MySQL服务将作为systemd服务自动启动。你可以运行 sudo systemctl status mysql命令验证MySQL服务器是否正在运行。 连接MySQL 当MySQL安装…

MySQL进阶45讲【10】MySQL为什么有时候会选错索引?

1 前言 前面我们介绍过索引&#xff0c;在MySQL中一张表其实是可以支持多个索引的。但是&#xff0c;写SQL语句的时候&#xff0c;并没有主动指定使用哪个索引。也就是说&#xff0c;使用哪个索引是由MySQL来确定的。 大家有没有碰到过这种情况&#xff0c;一条本来可以执行得…

【服务器】RAID(独立磁盘冗余阵列)

RAID&#xff08;独立磁盘冗余阵列&#xff09; 一、RAID的介绍二、RAID的分类#2-1 RAID 02-2 RAID 1#2-3 RAID 32-4 RAID 52-5 RAID 62-6 RAID 10(先做镜像&#xff0c;再做条带化)2-7 RAID 01&#xff08;先做条带&#xff0c;再做镜像&#xff09;2-8 RAID比较 三、磁盘阵列…

FANUC机器人示教器的菜单变成了图标,如何改成列表的形式?

FANUC机器人示教器的菜单变成了图标&#xff0c;如何改成列表的形式&#xff1f; 如下图所示&#xff0c;开机后按下MENU菜单键时&#xff0c;发现原来的列表形式变成了菜单图标的形式&#xff0c;同时在按F1-F5键时&#xff0c;提示&#xff1a;HMI模式-键不可用&#xff0c; …

蓝桥杯备战——12.超声波与测频代码优化

1.优化分析 昨天我在看原理图的发现超声波模块的反馈引脚P11刚好可以使用PCA模块0的捕获功能&#xff0c;我就想着把PCA功能留给超声波&#xff0c;然后测频功能还是改成定时器0来完成&#xff0c;然后前后台功能改成定时器1。 至于我为什么要这么改呢&#xff0c;看一下我原…

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key   登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…

【Mysql】整理

Mysql整理与总结 整理Mysql的基本内容供回顾。 参考&#xff1a; [1]. 掘金.MySQL三大日志(binlog,redolog,undolog)详解 [2]. Javaguide.MySQL三大日志(binlog、redo log和undo log)详解

陶哲轩如何用 GPT-4 辅助数学研究

关于陶哲轩&#xff08;Terence Tao&#xff09;用 GPT-4 进行数学研究的话题始于陶本人在 微软 Unlocked 上发表的 Embracing Change and Resetting Expectations 一文。文中提到&#xff1a; …… I could feed GPT-4 the first few PDF pages of a recent math preprint and…

Zookeeper服务注册与发现实战

目录 设计思路 Zookeeper注册中心的优缺点 SpringCloudZookeeper实现微服务注册中心 第一步&#xff1a;在父pom文件中指定Spring Cloud版本 第二步&#xff1a;微服务pom文件中引入Spring Cloud Zookeeper注册中心依赖 第三步&#xff1a; 微服务配置文件application.y…

47 mmap 的实现

前言 mmap 函数经常是和 普通的 bio 进行一个参照对比 mmap 相比于 bio 减少了一次 系统空间 到 用户空间 的拷贝操作 普通的 bio 的流程可以参见这里 从磁盘读取数据到内存的调试 这里 我们来看一下 mmap 测试用例 测试用例如下, 仅仅是一个 mmap 的一个简单的使用 …