Jeesite 登录逻辑分析

2023-11-10

最近项目需求研究免登录进入jeesite系统,于是对jeesite的登录逻辑进行了研究。

一:当用户从url访问jeesite系统时,首先会通过下面方法。 

@RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET)
	public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
		Principal principal = UserUtils.getPrincipal();

//		// 默认页签模式
//		String tabmode = CookieUtils.getCookie(request, "tabmode");
//		if (tabmode == null){
//			CookieUtils.setCookie(response, "tabmode", "1");
//		}
		
		if (logger.isDebugEnabled()){
			logger.debug("login, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}
		
		// 如果已登录,再次访问主页,则退出原账号。
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){
			CookieUtils.setCookie(response, "LOGINED", "false");
		}
		
		// 如果已经登录,则跳转到管理首页
		if(principal != null && !principal.isMobileLogin()){
			return "redirect:" + adminPath;
		}
		return "modules/sys/sysLogin";
	}
public static Principal getPrincipal(){
		try{
			Subject subject = SecurityUtils.getSubject();
			Principal principal = (Principal)subject.getPrincipal();
			if (principal != null){
				return principal;
			}
//			subject.logout();
		}catch (UnavailableSecurityManagerException e) {
			
		}catch (InvalidSessionException e){
			
		}
		return null;
	}
public static Subject getSubject() {

		/*  54*/ Subject subject = ThreadContext.getSubject();
		/*  55*/ if (subject == null) {
			/*  56*/ subject = (new org.apache.shiro.subject.Subject.Builder()).buildSubject();
			/*  57*/ ThreadContext.bind(subject);
		}
		/*  59*/ return subject;
	}

首先从UserUtils获取Principal,然后Principal是由Subject强转而来的,Subject由SecurityUtils获取的,具体代码在上面,当系统登录成功的时候ThreadContext会存储Subject信息,所以上面才可以获取到。当登录超时或未登录时,ThreadContext获取不到Subject会重新新建个subject并bind到ThreadContext中。系统根据Principal中的信息判断当前用户是否登录过。

二:当用户从登录页面进行登录时

    jeeste登录页面是sysLogin.jsp。主要就是个form表单提交

<form id="loginForm" class="form-signin" action="${ctx}/login" method="post">

在spring-context-shiro.xml配置了安全认证过滤器执行formAuthenticationFilter

<!-- 安全认证过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" /><!-- 
		<property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" /> -->
		<property name="loginUrl" value="${adminPath}/login" />
		<property name="successUrl" value="${adminPath}?login" />
		<property name="filters">
            <map>
                <!-- <entry key="cas" value-ref="casFilter"/> -->
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </map>
        </property>
		<property name="filterChainDefinitions">
			<ref bean="shiroFilterChainDefinitions"/>
		</property>
	</bean>

根据请求信息创建token然后传给SystemAuthorizingRealm中的doGetAuthenticationInfo进行认证

protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
		String username = getUsername(request);
		String password = getPassword(request);
		if (password==null){
			password = "";
		}
		boolean rememberMe = isRememberMe(request);
		String host = StringUtils.getRemoteAddr((HttpServletRequest)request);
		String captcha = getCaptcha(request);
		boolean mobile = isMobileLogin(request);
		return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile);
	}
/**
	 * 认证回调函数, 登录时调用
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		
		int activeSessionSize = getSystemService().getSessionDao().getActiveSessions(false).size();
		if (logger.isDebugEnabled()){
			logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, token.getUsername());
		}
		
		// 校验登录验证码
		if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){
			Session session = UserUtils.getSession();
			String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
			if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){
				throw new AuthenticationException("msg:验证码错误, 请重试.");
			}
		}
		
		// 校验用户名密码
		User user = getSystemService().getUserByLoginName(token.getUsername());
		if (user != null) {
			if (Global.NO.equals(user.getLoginFlag())){
				throw new AuthenticationException("msg:该已帐号禁止登录.");
			}
			byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));
			return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), 
					user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
		} else {
			return null;
		}
	}

doGetAuthenticationInfo会根据token中的信息生成SimpleAuthenticationInfo,交给info认证。

return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), 
					user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
public void merge(AuthenticationInfo info) {

		/* 194*/ if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty())
			/* 195*/ return;

		/* 198*/ if (principals == null) {
			/* 199*/ principals = info.getPrincipals();
		} else {
			/* 201*/ if (!(principals instanceof MutablePrincipalCollection))
				/* 202*/ principals = new SimplePrincipalCollection(principals);

			/* 204*/ ((MutablePrincipalCollection) principals).addAll(info.getPrincipals());
		}

		/* 213*/ if (credentialsSalt == null && (info instanceof SaltedAuthenticationInfo))
			/* 214*/ credentialsSalt = ((SaltedAuthenticationInfo) info).getCredentialsSalt();

		/* 217*/ Object thisCredentials = getCredentials();
		/* 218*/ Object otherCredentials = info.getCredentials();

		/* 220*/ if (otherCredentials == null)
			/* 221*/ return;

		/* 224*/ if (thisCredentials == null) {
			/* 225*/ credentials = otherCredentials;
			/* 226*/ return;
		}

		/* 229*/ if (!(thisCredentials instanceof Collection)) {
			/* 230*/ Set newSet = new HashSet();
			/* 231*/ newSet.add(thisCredentials);
			/* 232*/ setCredentials(newSet);
		}

		/* 236*/ Collection credentialCollection = (Collection) getCredentials();
		/* 237*/ if (otherCredentials instanceof Collection)
			/* 238*/ credentialCollection.addAll((Collection) otherCredentials);

		/* 240*/ else
			/* 240*/ credentialCollection.add(otherCredentials);
	}

	public boolean equals(Object o) {

		/* 253*/ if (this == o)
			/* 253*/ return true;
		/* 254*/ if (!(o instanceof SimpleAuthenticationInfo))
			/* 254*/ return false;

		/* 256*/ SimpleAuthenticationInfo that = (SimpleAuthenticationInfo) o;

		/* 259*/ return principals == null ? that.principals == null : principals.equals(that.principals);
	}

如果认证失败会执行LoginController中的loginFail方法,并且返回登录页面

/**
	 * 登录失败,真正登录的POST请求由Filter完成
	 */
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST)
	public String loginFail(HttpServletRequest request, HttpServletResponse response, Model model) {
		Principal principal = UserUtils.getPrincipal();
		
		// 如果已经登录,则跳转到管理首页
		if(principal != null){
			return "redirect:" + adminPath;
		}

		String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
		boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
		boolean mobile = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_MOBILE_PARAM);
		String exception = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
		String message = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM);
		
		if (StringUtils.isBlank(message) || StringUtils.equals(message, "null")){
			message = "用户或密码错误, 请重试.";
		}

		model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_MOBILE_PARAM, mobile);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, message);
		
		if (logger.isDebugEnabled()){
			logger.debug("login fail, active session size: {}, message: {}, exception: {}", 
					sessionDAO.getActiveSessions(false).size(), message, exception);
		}
		
		// 非授权异常,登录失败,验证码加1。
		if (!UnauthorizedException.class.getName().equals(exception)){
			model.addAttribute("isValidateCodeLogin", isValidateCodeLogin(username, true, false));
		}
		
		// 验证失败清空验证码
		request.getSession().setAttribute(ValidateCodeServlet.VALIDATE_CODE, IdGen.uuid());
		
		// 如果是手机登录,则返回JSON字符串
		if (mobile){
	        return renderString(response, model);
		}
		
		return "modules/sys/sysLogin";
	}

如果登录成功会进行LoginController中的index方法,进入管理页面。

@RequiresPermissions("user")
	@RequestMapping(value = "${adminPath}")
	public String index(HttpServletRequest request, HttpServletResponse response) {
		Principal principal = UserUtils.getPrincipal();

		// 登录成功后,验证码计算器清零
		isValidateCodeLogin(principal.getLoginName(), false, true);
		if (logger.isDebugEnabled()){
			logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}
		
		// 如果已登录,再次访问主页,则退出原账号。
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){
			String logined = CookieUtils.getCookie(request, "LOGINED");
			if (StringUtils.isBlank(logined) || "false".equals(logined)){
				CookieUtils.setCookie(response, "LOGINED", "true");
			}else if (StringUtils.equals(logined, "true")){
				UserUtils.getSubject().logout();
				return "redirect:" + adminPath + "/login";
			}
		}
		
		// 如果是手机登录,则返回JSON字符串
		if (principal.isMobileLogin()){
			if (request.getParameter("login") != null){
				return renderString(response, principal);
			}
			if (request.getParameter("index") != null){
				return "modules/sys/sysIndex";
			}
			return "redirect:" + adminPath + "/login";
		}
		
//		// 登录成功后,获取上次登录的当前站点ID
//		UserUtils.putCache("siteId", StringUtils.toLong(CookieUtils.getCookie(request, "siteId")));

//		System.out.println("==========================a");
//		try {
//			byte[] bytes = com.thinkgem.jeesite.common.utils.FileUtils.readFileToByteArray(
//					com.thinkgem.jeesite.common.utils.FileUtils.getFile("c:\\sxt.dmp"));
//			UserUtils.getSession().setAttribute("kkk", bytes);
//			UserUtils.getSession().setAttribute("kkk2", bytes);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		for (int i=0; i<1000000; i++){
			//UserUtils.getSession().setAttribute("a", "a");
			request.getSession().setAttribute("aaa", "aa");
		}
//		System.out.println("==========================b");
		return "modules/sys/sysIndex";
	}
还有些ssm的内容大家应该都知道。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jeesite 登录逻辑分析 的相关文章

  • 【进制转换】二进制,十进制,八进制,16进制

    1 二进制与十进制相互转换 二进制转为十进制 0000 0110转换为10进制 二进制里面没有 个位 十位 百位 只能通过从左到右或者从右到左第几位来描述 从右往左开始 第一位是0 进制的基数是2 那么就是0 20 第二位是1 就是1 21
  • Svelte3聊天室

    Python微信订餐小程序课程视频 https edu csdn net course detail 36074 Python实战量化交易理财系统 https edu csdn net course detail 35475 基于svelt
  • chatgpt赋能python:Python长浮点型介绍

    Python长浮点型介绍 Python是一种强大的编程语言 通过其众多的数据类型 使开发人员可以快速开发复杂的应用程序 其中 Python长浮点型就是Python支持的一种数据类型 长浮点型是指Python可以处理的浮点数的精度可以高达25
  • vue---UI框架elementUI实现系统登录注册页

    https blog csdn net maidu xbd article details 87943243已经搭建好了vue开发环境 在本博客中 来介绍些结合element ui实现登录注册界面 界面效果展示如下图 实现的功能包括 首先安
  • 如何轻松实现内网穿透?异地办公?调试微信小程序?

    步骤很简单 只需三步 1 从 https www i996 me 获取获取你的公网域名和访问Token 项目托管在 https github com bugfan i996 2 在Max Linux 环境下 Windows类似 打开一个终端
  • SQL Server2012如何更改服务器的名称

    一 事情起因 三层架构有个小问题 总是报各种错误 昨下午花费了半天时间准备把这个问题解决掉 未果 后来尝试了连接东哥的数据库 程序奇迹般的能运行了 东哥推测可能是我SQL Server 2012安装有问题 于是开始了尝试之旅 二 错误描述
  • MybatisPlus核心功能——实现CRUD增删改查操作 (包含条件构造器)

    优质资源分享 学习路线指引 点击解锁 知识定位 人群定位 Python实战微信订餐小程序 进阶级 本课程是python flask 微信小程序的完美结合 从项目搭建到腾讯云部署上线 打造一个全栈订餐系统 Python量化交易实战 入门级 手
  • 人工智能之深度学习-初始环境搭建(安装Anaconda3和TensorFlow2步骤详解)

    Python微信订餐小程序课程视频 https edu csdn net course detail 36074 Python实战量化交易理财系统 https edu csdn net course detail 35475 前言 本篇文章
  • ios接入GameCenter登录

    iOS接入GameCenter登录很简单 首先 在target gt Capabilities中打开GameCenter配置 这里的内购 In App Purchase 是因为我需要接内购的SDK 所以我把这个 In App Purchas
  • 计算机含金量最高的证书

    第一种证书 计算机技术与软件专业资格考试证书 计算机技术与软件专业资格考试证书 是由国家人力资源和社会保障部 工业和信息化部领导的国家级考试 该考试分为 5 个专业类别 并分设了高 中 初级专业资格考试 共 28 个资格的考核 也是用人单位
  • 搞懂了Vue对象与实例的区别!

    很多人把Vue对象和Vue实例混为一谈 但它们还是有区别的 Vue构造函数就像一台智能手机的设计图纸 定义了这款手机的总体结构和组件 而每部依照设计图组装出来的真实手机 就是Vue实例 设计图上注明了屏幕尺寸 CPU型号等静态信息 对应Vu
  • 软件工程学习日记(4)----面向数据流的设计方法

    用面向数据流的方法设计下列系统的软件结构 问题回顾 为方便储户 某银行拟开发计算机储蓄系统 储户填写的存款单或取款单由业务员输入系统 如果是存款 系统记录存款人姓名 住址 存款类型 存款日期 利率等信息 并印出存款单给储户 如果是取款 系统
  • python拼接两个或者多个视频文件

    拼接不同分辨率的视频文件 import os import linecache 读取指定路径下的所有文件并放入到列表中 root workspace videos codec videos codec evp test h264 file
  • 深入理解计算机系统-笔记

    计算机系统漫游 程序 程序的生命周期从一个源程序 源文件 开始 即程序员利用编辑器创建并保存的文本文件 如文件名为hello c的c语言程序 源程序是由0和1组成的位序列 8个位被组织成一组 称为字节 每个字节表示程序中的某个文本字符 这种
  • [ Shell ] 通过 Shell 脚本导出 CDL 网表

    Python微信订餐小程序课程视频 https edu csdn net course detail 36074 Python实战量化交易理财系统 https edu csdn net course detail 35475 https b
  • chatgpt赋能python:Python如何获取微信聊天记录:详细教程

    Python如何获取微信聊天记录 详细教程 在当前的数字时代 如何快速 便捷地获取信息是困扰每个人的问题 随着移动互联网的发展 微信成为了人们交流沟通的主要工具之一 在这样的背景下 如何获取微信聊天记录成为了一项非常重要的技能 在某些场合中
  • chatgpt赋能python:Python如何优化中文SEO

    Python如何优化中文SEO Python 作为一种流行的编程语言 可以用来开发各种不同的应用程序 当涉及到网络营销和搜索引擎优化 SEO 时 Python的功能也非常有用 在本篇文章中 我们将介绍如何使用Python来优化中文SEO 以
  • chatgpt赋能python:如何用Python实现抢购?

    如何用Python实现抢购 Python是一种灵活多样的编程语言 可以用它来完成各种任务 其中之一就是抢购 在电商大促销的节日 抢购商品通常需要竞争非常激烈 但是使用Python编写抢购脚本可以让您获得更高的成功率 以下是一些建议 通过Py
  • 【CSDN】删除文章后,浏览量会减少吗?了解软删除和硬删除

    hello 我是小索奇 如果你也在博客写作的话 有没有考虑到一个问题 文章删除后 浏览量会减少吗 下面就给大家阐述一下 当在CSDN中删除已发布的文章后 该文章的浏览量统计会有以下情况 软删除状态的文章 浏览量统计会保留 不会下降或者重置
  • 计算机网络4--Internet结构

    本页内容 1 基本结构 2 结构图解 3 层次结构图解 1 基本结构 a 端系统通过接入ISP access ISPs 连接到Internet b 接入ISP必须进一步互连 保证任意两个主机可以互相发送分组 c 构成复杂的网络互连的网络 2

随机推荐

  • kali linux 安装搜狗输入法(解决安装后只有搜狗五笔的问题)

    kali 安装搜狗输入法 解决安装后之后只有搜狗五笔的问题 第一步 去搜狗输入法的官方网站下载搜狗输入法 https pinyin sogou com linux 下载后打开文件所在路径 sougoupinyin 2 3 1 0112 am
  • unity读取json文件乱码以及Invalid character 'v' in input string异常解决方案

    先说PC端吧 PC端乱码很容易解决 itemsTable JsonMapper ToObject File ReadAllText Application dataPath Scripts Json itemsTable json Enco
  • Linux 安装软件 常见问题 x86 or x64

    Linux 安装软件 常见问题 x86 or x64 平民资料 x64 是指CPU是64位版本的 x86 是指CPU是32位版本的 如果你的CPU是64位的 可以安装64位的 也可以安装32位的 反过来只能安装32位的 RedHat Lin
  • React 路由基本使用

    代码示例 有Logint和Layout组件 import React from react import BrowserRouter as Router Redirect Route Switch from react router dom
  • python重命名文件excel,在excel电子表格的文件夹python上重命名多个文件

    I am pretty new at Python and I want to automate a process that takes a lot of my time but now I need to rename about 20
  • js 如何判断属性,包括多级对象的状况

    js目前没有一个明确的方法去判断对象是否存在 尤其是出现多级属性 对象 的情况 一旦一个不存在的属性跨级取 就会报错 undefined 因此考虑封装一个通用的方法去专门检测 如果存在属性返回true 反之返回falsefunction c
  • # HTB-Tier2- Oopsie

    HTB Tier2 Oopsie Tags PHP Web Custom Applications Session Handling Apache Penetration Tester Level 1 Reconaisance Web Si
  • 在 uni-app 中选中奇偶子元素

    问题描述 在 uni app 中 使用 nth child 选择器选择奇偶子元素不像预期那样生效 原代码 nth child 2n 选择偶数个子元素 nth child 2n 1 选择奇数个子元素 奇数子元素 issueData item
  • redux的理解及其工作原理?工作流程?

    理解 redux是一个用于管理JavaScript应用程序状态的可预测状态容器 它是一个独立于任何特定UI库的状态管理库 但在React应用中广泛使用 工作原理可以概括为一下几个关键概念 1 store 存储 redux应用的状态 Stat
  • 调试笔记之雨过天晴多点还原软件MBR实例

    BY SUDAMI 为了能够调试多点还原软件 雨过天晴 的启动代码 目前有2种方式 引用 1 在Bochs调试器上装Windows XP系统 然后用Bochs单步调试 不过光安装操作系统就得花20个小时以上 2 用Wnhex克隆整个磁盘 配
  • 求点集中存在的点,满足:其x、y坐标值不同时小于点集中任意一点的x、y坐标值

    问题描述 对于平面上的两个点p1 x1 y1 和p2 x2 y2 如果x1 lt x2且y1 lt y2 则p2支配p1 给定平面上的n个点 请设计算法求其中没有被任何其他点支配的点 换句话说 即 求点集中存在的点 满足 其x y坐标值不同
  • Java实现杨辉三角

    杨辉三角的模型 分析 1 最外层的数字始终是 1 2 每个数等于它上方两数之和 public class Yanghui public static void main String args int yanghui new int 10
  • springcloud配合eureka遇到的巨坑

    springcloud配合eureka遇到一个巨坑 这个问题困扰了楼主整整3天 问题描述 项目在idea能够启动 注册服务 心跳检测一切正常 但是打包后放入服务器中 发现项目启动正常 服务注册正常 但是过了30秒后 eureka开始报错 报
  • [JSP暑假实训] 五.MyEclipse+Servlet+JSP实现火车票网站注册操作及登陆验证

    本系列文章是作者暑假给学生进行实训分享的笔记 主要介绍MyEclipse环境下JSP网站开发 包括JAVA基础 网页布局 数据库基础 Servlet 前端后台数据库交互 DAO等知识 前一篇文章讲解了MyEclipse Servlet JS
  • 用户管理相关命令

    用户管理相关命令 实验目的 通过对用户管理相关命令进行练习 能够对linux中用户和组的维护和管理工作熟练处理 实验内容 1 su命令 切换另一用户 切换主用户时需要输入密码 2 用户相关命令 useradd 创建新用户 passwd us
  • android 检查otg,怎么查看手机是否支持otg

    怎么查看手机是否支持otg很多同学都遇到了这个问题 那么该如何解决呢 请看IEfans小编给大家带来的查看手机是否支持otg方法一览 希望对您有所帮助 工具 原料 手机 VIVO X6S A 系统 PD1415BA A 3 13 10And
  • LeetCode141:环形链表

    给你一个链表的头节点 head 判断链表中是否有环 如果链表中有某个节点 可以通过连续跟踪 next 指针再次到达 则链表中存在环 为了表示给定链表中的环 评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置 索引从 0 开始 注意
  • Non-resolvable parent POM for解决

    在运行maven项目是出现CIA列错误提示 INFO Scanning for projects ERROR ERROR Some problems were encountered while processing the POMs FA
  • 机器学习资源大全中文版

    中午版翻译转载自 https github com jobbole awesome machine learning cn 英文版原文转载自 https github com josephmisiti awesome machine lea
  • Jeesite 登录逻辑分析

    最近项目需求研究免登录进入jeesite系统 于是对jeesite的登录逻辑进行了研究 一 当用户从url访问jeesite系统时 首先会通过下面方法 RequestMapping value adminPath login method