CAS单点登录-单用户登录(十九)

2024-05-15 17:48

本文主要是介绍CAS单点登录-单用户登录(十九),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CAS单点登录-单用户登录(十九)

简介

所谓“单用户单账户登录”是指:在同一系统中,一个用户名不能在两个地方同时登录。

如:
当某账号在 A 处登录后,在未退出的情况下,如果再到 B 处登录,那么,系统会挤下 A 处登录的账号

程序逻辑

我们一路学习cas过来应该知道如下知识

  1. 维持一个用户状态是用tgt
  2. 用户登录成功后tgt会创建
  3. 业务系统验证成功是采用st的校验
  4. 用户注销相当于删除tgt
  5. 删除tgt采用CentralAuthenticationService.destroyTicketGrantingTicket

有以上的知识我们即可对其他用户的提出,程序应该满足以下逻辑:

  1. 监听tgt创建事件
  2. 获取用户id,以及tgt
  3. 根据用户id,认证方式clientName寻找所有的tgt
  4. 过滤非当前用户的tgt的所有tgt
  5. 删除过滤后的tgt(正确的逻辑过滤后一般情况剩下一个,因为已经单用户登录了)

第三点详解:
为什么要采用clientName进行过滤呢,因为认证平台可能通过restful认证,qq、github、微信的OAuth2认证等等,所以认证方式不同,最后的用户id以及clientName会不同,所以要根据用户认证方式以及id,找到所有该用户的认证方式进行删除tgt,否则会出现,oauth2登录的用户用账号登录无法强制注销

实战

TGT创建监听

这个监听是为了用户登录成功后对其他用户进行剔除

TGTCreateEventListener.java

/** 版权所有.(c)2008-2017. 卡尔科技工作室*/package com.carl.sso.support.single.listener;import com.carl.sso.support.single.service.IUserIdObtainService;
import com.carl.sso.support.single.service.TriggerLogoutService;
import org.apereo.cas.support.events.ticket.CasTicketGrantingTicketCreatedEvent;
import org.apereo.cas.ticket.TicketGrantingTicket;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;import javax.validation.constraints.NotNull;
import java.util.List;/*** 识别事件然后删除** @author Carl* @version 创建时间:2017/11/29*/
public class TGTCreateEventListener {private TriggerLogoutService logoutService;private IUserIdObtainService service;public TGTCreateEventListener(@NotNull TriggerLogoutService logoutService, @NotNull IUserIdObtainService service) {this.logoutService = logoutService;this.service = service;}@EventListener@Asyncpublic void onTgtCreateEvent(CasTicketGrantingTicketCreatedEvent event) {TicketGrantingTicket ticketGrantingTicket = event.getTicketGrantingTicket();String id = ticketGrantingTicket.getAuthentication().getPrincipal().getId();String tgt = ticketGrantingTicket.getId();String clientName = (String) ticketGrantingTicket.getAuthentication().getAttributes().get("clientName");//获取可以认证的idList<String> authIds = service.obtain(clientName, id);if (authIds != null) {//循环触发登出authIds.forEach(authId -> logoutService.triggerLogout(authId, tgt));}}
}

剔除过滤用户

根据用户id,tgt,筛选出用户,并剔除

TriggerLogoutService.java

/** 版权所有.(c)2008-2017. 卡尔科技工作室*/package com.carl.sso.support.single.service;import org.apereo.cas.CentralAuthenticationService;
import org.apereo.cas.authentication.Authentication;
import org.apereo.cas.ticket.Ticket;
import org.apereo.cas.ticket.TicketGrantingTicket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Collection;/*** 登出触发器** @author Carl* @date 2017/11/29*/
public class TriggerLogoutService {private static final Logger LOGGER = LoggerFactory.getLogger(TriggerLogoutService.class);private CentralAuthenticationService service;public TriggerLogoutService(CentralAuthenticationService service) {this.service = service;}/*** 触发其他用户退出** @param id  用户id* @param tgt 当前登录的tgt*/public void triggerLogout(String id, String tgt) {//找出用户id,并且不为当前tgt的,这里应当考虑数据性能,直接筛选用户再筛选tgtCollection<Ticket> tickets = this.service.getTickets(ticket -> {if(ticket instanceof TicketGrantingTicket) {TicketGrantingTicket t = ((TicketGrantingTicket)ticket).getRoot();Authentication authentication = t.getAuthentication();return t != null && authentication != null&& authentication.getPrincipal() != null && id.equals(authentication.getPrincipal().getId())&& !tgt.equals(t.getId());} else {return false;}});if (tickets != null && tickets.size() > 0) {LOGGER.info(String.format("[%s]强制强制注销%s", id, tickets.size()));}//发出注销for (Ticket ticket : tickets) {service.destroyTicketGrantingTicket(ticket.getId());}}
}

获取用户id

UserIdObtainServiceImpl.java

/** 版权所有.(c)2008-2017. 卡尔科技工作室*/package com.carl.sso.support.single.service;import java.util.ArrayList;
import java.util.List;/*** @author Carl* @version 创建时间:2017/11/29*/
public class UserIdObtainServiceImpl implements IUserIdObtainService {public UserIdObtainServiceImpl() {}@Overridepublic List<String> obtain(String clientName, String id) {//由于这里目前只做测试所以只返回当前的id,在正常的情况逻辑应该如下//根据校验client以及登录的id找到其他同一个用户的所有校验id返回,如通过邮箱登录的id,通过github登录的id等等List<String> ids = new ArrayList<>();ids.add(id);return ids;}
}

spring配置注册

SingleLogoutTriggerConfiguration.java

/** 版权所有.(c)2008-2017. 卡尔科技工作室*/package com.carl.sso.support.single.config;import com.carl.sso.support.single.listener.TGTCreateEventListener;
import com.carl.sso.support.single.service.TriggerLogoutService;
import com.carl.sso.support.single.service.UserIdObtainServiceImpl;
import org.apereo.cas.CentralAuthenticationService;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 登出配置** @author Carl* @date 2017/11/29*/
@Configuration("singleLogoutTriggerConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class SingleLogoutTriggerConfiguration {@Autowiredprivate CentralAuthenticationService centralAuthenticationService;/*** 触发登出服务** @return 触发登出服务*/@Beanprotected TriggerLogoutService triggerLogoutService() {return new TriggerLogoutService(centralAuthenticationService);}@Bean//注册事件监听tgt的创建protected TGTCreateEventListener tgtCreateEventListener() {TGTCreateEventListener listener = new TGTCreateEventListener(triggerLogoutService(), new UserIdObtainServiceImpl());return listener;}
}

测试

代码提交可以参考github提交

测试流程:

在chrome浏览器登陆,然后在IE浏览器登陆同样的账号,chrome浏览器的用户已登出

下载代码尝试:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aOLNA5A3-1611805583688)(https://img.shields.io/badge/downloads-v1.7.0=RC1-brightgreen.svg)] 其他版本可以到GitHub或者码云查看

发现一些意外的事情可以考虑翻翻前面的博客进行学习哦

作者联系方式

如果技术的交流或者疑问可以联系或者提出issue。

邮箱:huang.wenbin@foxmail.com

QQ: 756884434 (请注明:SSO-CSDN)

这篇关于CAS单点登录-单用户登录(十九)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/992506

相关文章

90%的人第一步就错了! 顺利登录wifi路由器后台的技巧

《90%的人第一步就错了!顺利登录wifi路由器后台的技巧》登录Wi-Fi路由器,其实就是进入它的后台管理页面,很多朋友不知道该怎么进入路由器后台设置,感兴趣的朋友可以花3分钟了解一下... 你是不是也遇到过这种情况:家里网速突然变慢、想改WiFi密码却不知道从哪进路由器、新装宽带后完全不知道怎么设置?别慌

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

Spring Security重写AuthenticationManager实现账号密码登录或者手机号码登录

《SpringSecurity重写AuthenticationManager实现账号密码登录或者手机号码登录》本文主要介绍了SpringSecurity重写AuthenticationManage... 目录一、创建自定义认证提供者CustomAuthenticationProvider二、创建认证业务Us

Springboot项目登录校验功能实现

《Springboot项目登录校验功能实现》本文介绍了Web登录校验的重要性,对比了Cookie、Session和JWT三种会话技术,分析其优缺点,并讲解了过滤器与拦截器的统一拦截方案,推荐使用JWT... 目录引言一、登录校验的基本概念二、HTTP协议的无状态性三、会话跟android踪技术1. Cook

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

nginx 负载均衡配置及如何解决重复登录问题

《nginx负载均衡配置及如何解决重复登录问题》文章详解Nginx源码安装与Docker部署,介绍四层/七层代理区别及负载均衡策略,通过ip_hash解决重复登录问题,对nginx负载均衡配置及如何... 目录一:源码安装:1.配置编译参数2.编译3.编译安装 二,四层代理和七层代理区别1.二者混合使用举例

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.

Java中的登录技术保姆级详细教程

《Java中的登录技术保姆级详细教程》:本文主要介绍Java中登录技术保姆级详细教程的相关资料,在Java中我们可以使用各种技术和框架来实现这些功能,文中通过代码介绍的非常详细,需要的朋友可以参考... 目录1.登录思路2.登录标记1.会话技术2.会话跟踪1.Cookie技术2.Session技术3.令牌技