当前位置: 首页 > news >正文

常用登录加密之Shiro与Spring Security的使用对比

        Shiro与Spring Security都是主流的身份认证和权限控制安全框架,Shiro偏向于前后端不分离平台,而Spring Security更偏向于前后端分离平台。接下来简单列一下两种登录验证的执行流程和示例,了解实际运用中的登录执行流程,然后重点剖析一下密码验证的过程。其实,密码验证的本质就是比较用户输入的凭证(密码)和存储的凭证(加密后的密码)是否匹配 ,如果一致,则表示密码验证通过。

文章目录

    • Spring Security的登录过程
      • 1.导入依赖
      • 2.UsernamePasswordAuthenticationToken
      • 3.UserDetailsServiceImpl
      • 4.账号密码验证说明(重点)
        • 加密说明
        • 加密特点:不需要提供盐、每次加密结果都不一样
        • 加密示例
    • Shiro的登录过程
      • 1.导入依赖
      • 2.UsernamePasswordToken
      • 3.UserRealm
      • 4.账号密码验证说明(重点)
        • 加密说明
        • 加密特点:需要提供盐、加密的时候需要传入登录用户名、加密结果都是一样的
        • 加密示例

Spring Security的登录过程

1.导入依赖

		<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-core</artifactId></dependency>

2.UsernamePasswordAuthenticationToken

在登录方法中通过UsernamePasswordAuthenticationToken把用户名、密码信息封装起来,使用AuthenticationManager的authenticate方法并传入UsernamePasswordAuthenticationToken对象

@RestController
public class LoginController {@Resourceprivate AuthenticationManager authenticationManager;@RequestMapping("/login")public R login(String userName, String password){Authentication authentication = null;try {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName, password);AuthenticationContextHolder.setContext(authenticationToken);// 该方法会去调用UserDetailsServiceImpl.loadUserByUsernameauthentication = authenticationManager.authenticate(authenticationToken);} catch (Exception e) {e.printStackTrace();return R.error();}//登录认证成功,生成token返回LoginUser loginUser = (LoginUser) authentication.getPrincipal();String token = getToken(loginUser); return R.ok().setData(token);}private String getToken(LoginUser loginUser) {//TODO 按照自己的业务需求生成return null;}
}

上下文对象,用来存放身份认证信息

/*** 上下文对象,用来存放身份认证信息*/
public class AuthenticationContextHolder {private static final ThreadLocal<Authentication> contextHolder = new ThreadLocal<>();public static Authentication getContext() {return contextHolder.get();}public static void setContext(Authentication context) {contextHolder.set(context);}public static void clearContext() {contextHolder.remove();}
}

3.UserDetailsServiceImpl

①同时定义UserDetailsServiceImpl类实现UserDetailsService,并重写loadUserByUsername方法,上面步骤就会执行到此方法中;
②在loadUserByUsername方法中通过上下文传值AuthenticationContextHolder获取到登录的用户名和密码;
③进行账号、密码验证

@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserService userService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userService.selectUserByUserName(username);boolean state = validate(user); //验证用户信息if (!state) {//账号、密码验证失败throw new UsernameNotFoundException("账号、密码验证失败");}//生成UserDetails信息返回UserDetails userDetails = new LoginUser();return userDetails;}private boolean validate(User user){Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();String password = usernamePasswordAuthenticationToken.getCredentials().toString();//验证账号、密码return new BCryptPasswordEncoder().matches(password, user.getPassword());}
}

4.账号密码验证说明(重点)

加密说明

Spring Security主要使用BCryptPasswordEncoder进行加密的,BCryptPasswordEncoder用SHA-256+随机盐+密钥对密码进行加密,这种加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,无法根据密文推算出明文。BCryptPasswordEncoder的加密过程中,同一个密码,由于盐是随机的,所以每次加密的结果都是不一样的,然后就是明文密码的hash值与数据库中存储密码hash值进行比较。

加密特点:不需要提供盐、每次加密结果都不一样
加密示例
	public static void main(String[] args) {//初始化BCryptPasswordEncoderBCryptPasswordEncoder encoder = new BCryptPasswordEncoder();//原始密码String initPwd = "123456";String encode1 = encoder.encode(initPwd);System.out.println("1次加密结果:"+encode1);String encode2 = encoder.encode(initPwd);System.out.println("2次加密结果:"+encode2);String encode3 = encoder.encode(initPwd);System.out.println("3次加密结果:"+encode3);boolean b1 = encoder.matches(initPwd, encode1);System.out.println("1次加密认证:"+b1);boolean b2 = encoder.matches(initPwd, encode2);System.out.println("2次加密认证:"+b2);boolean b3 = encoder.matches(initPwd, encode3);System.out.println("3次加密认证:"+b3);}

运行结果:

1次加密结果:$2a$10$8NfgZSeUG8mCApNeJumsg.Z6k3SF1HrGPB0FPuLDlFy2jYF.uHYAm
2次加密结果:$2a$10$.PTFbG0qwMHiQLgA5SY/pOOcHCUP7gZQvQYAEv6RRaE0R3Wc9e.hW
3次加密结果:$2a$10$YFI4vgXpnYlcfsqpplqJ1OjL8JczZSqYWjL0jIkmggTpe7cSuaaNi
1次加密认证:true
2次加密认证:true
3次加密认证:true



Shiro的登录过程

1.导入依赖

		<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-crypto-hash</artifactId><version>1.6.0</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.6.0</version></dependency>

2.UsernamePasswordToken

通过UsernamePasswordToken这个类会将用户登录信息封装起来,生成Token,然后通过SecurityUtils下的subject传入token执行登录方法

@RestController
public class LoginController {@RequestMapping("/login")public R login(String userName, String password){UsernamePasswordToken token = new UsernamePasswordToken(userName, password);Subject subject = SecurityUtils.getSubject();try {subject.login(token);//验证通过,登录成功return R.ok();} catch (AuthenticationException e) {e.printStackTrace();//用户或密码错误,验证失败return R.error();}}
}

3.UserRealm

①认证器会将Token分解开来,分成账号和密码,并通过Relam这个桥梁向数据库进行求证;
②然后自定义UserRealm类并继承AuthorizingRealm方法,重写doGetAuthenticationInfo方法中就可以从token中获取用户账号、密码信息;
③进行账号、密码验证

public class UserRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//授权方法 TODOreturn null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//登录方法UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;String userName = upToken.getUsername();String password = new String(upToken.getPassword());//执行登录验证User user = null;try {//验证账号、密码user = validate(userName, password);} catch (Exception e) {throw new AuthenticationException(e.getMessage(), e);}return new SimpleAuthenticationInfo(user, password, getName());}private User validate(String userName, String password) throws AuthenticationException {User user = userService.selectUserByUserName(userName);if (user == null) {throw new AuthenticationException("用户不存在");}//输入密码加密String inputPwd = encryptPassword(userName, password, user.getSalt());//数据库密码String dbPwd = user.getPassword();if (!inputPwd.equals(dbPwd)) {throw new AuthenticationException("用户名、密码验证失败");}return user;}private static String encryptPassword(String userName, String password, String salt) {return new Md5Hash(userName + password + salt).toHex().toString();}
}

4.账号密码验证说明(重点)

加密说明

Shiro主要使用的是MD5进行加密的,底层就是传入登录名、密码、盐,使用MD5进行hash加密计算,得到一个密文字符串,通常会把盐和这个密文字符串存入到数据库中。下次用户登录的时候,传入登录名和密码,从数据库中获取到盐,MD5加密生成此时的加密密文,与数据库中存储的加密密文进行匹配。如果一致则验证通过,如果不一致,则验证不通过。

加密特点:需要提供盐、加密的时候需要传入登录用户名、加密结果都是一样的
加密示例
	public static void main(String[] args) {//密文密码String dbPwd = "3d3e2e119996cedb7401025cced5c1b0";//用户名String userName = "admin";//盐String salt = "111111";//明文密码String inputPwd = "123456";String encryptPassword = encryptPassword(userName, inputPwd, salt);System.out.println("加密结果:"+encryptPassword);boolean b = dbPwd.equals(encryptPassword);System.out.println("认证结果:"+b);}public static String encryptPassword(String userName, String password, String salt) {return new Md5Hash(userName + password + salt).toHex().toString();}

运行结果:

加密结果:3d3e2e119996cedb7401025cced5c1b0
认证结果:true

相关文章:

常用登录加密之Shiro与Spring Security的使用对比

Shiro与Spring Security都是主流的身份认证和权限控制安全框架&#xff0c;Shiro偏向于前后端不分离平台&#xff0c;而Spring Security更偏向于前后端分离平台。接下来简单列一下两种登录验证的执行流程和示例&#xff0c;了解实际运用中的登录执行流程&#xff0c;然后重点剖…...

获取文件路径里的文件名(不包含扩展名)

“./abc/abc/llf.jpg” 写一个代码&#xff0c;让我获得“llf”这段字符串 import osfile_path "./abc/abc/llf.jpg" file_name os.path.splitext(os.path.basename(file_path))[0] print(file_name)在这个代码中&#xff0c;我们使用了os.path模块来处理文件路径…...

HiveSql语法优化二 :join算法

Hive拥有多种join算法&#xff0c;包括Common Join&#xff0c;Map Join&#xff0c;Bucket Map Join&#xff0c;Sort Merge Buckt Map Join等&#xff0c;下面对每种join算法做简要说明&#xff1a; Common Join Common Join是Hive中最稳定的join算法&#xff0c;其通过一个M…...

Leetcode—459.重复的子字符串【简单】

2023每日刷题&#xff08;五十九&#xff09; Leetcode—459.重复的子字符串 算法思想 巧解的算法思想 实现代码 从第一个位置开始到s.size()之前&#xff0c;看s字符串是否是ss的子串 class Solution { public:bool repeatedSubstringPattern(string s) {return (s s).fin…...

Mac安装Typora实现markdown自由

一、什么是markdown Markdown 是一种轻量级标记语言&#xff0c;创始人为约翰格鲁伯&#xff08;John Gruber&#xff09;。 它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成有效的 XHTML&#xff08;或者HTML&#xff09;文档。这种语言吸收了很多在电子邮…...

前后端传参格式

前端发送 Serialize()方法 是指将一个抽象的JavaScript对象&#xff08;数据结构&#xff09;转换成字符串。这个字符串可以利用标准格式发送到服务器&#xff0c;被视为URL查询字符串或者POST数据&#xff0c;或者由于复杂的AJAX请求。这个方法使用的数据结构可以是JavaScri…...

【后端学前端】第三天 css动画 动态搜索框(定位、动态设置宽度)

1、学习信息 视频地址&#xff1a;css动画 动态搜索框&#xff08;定位、动态设置宽度&#xff09;_哔哩哔哩_bilibili 2、源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>test3</title>…...

51.0/表单(详细版)

目录 51.1 输入元素 input 51.1.1 文本域 51.1.2 密码输入框 51.1.3 单选框 51.1.4 复选框 51.1.5 提交按钮 51.1.6 重置按钮 51.1.7 普通按钮 51.1.8 图片按钮 51.1.9 隐藏域 51.1.10 文件域 51.2 多行文本框 51.3 下拉列表框 51.4 表单的综合示例 表单是网页中…...

动态规划(Dynamic Programming)

动态规划&#xff08;Dynamic Programming&#xff09;&#xff1a;是运筹学的一种最优化方法&#xff0c;只不过在计算机问题上应用比较多 DP常见步骤&#xff1a; 暴力递归/穷举记忆化搜索&#xff08;傻缓存 递归&#xff09;,使用备忘录/ DP Table 来优化穷举过程严格表结…...

linux使用文件描述符0、1和2来处理输入和输出

文件描述符012 在Linux中&#xff0c;文件描述符0、1和2分别代表标准输入&#xff08;stdin&#xff09;、标准输出&#xff08;stdout&#xff09;和标准错误&#xff08;stderr&#xff09;。它们用于处理进程的输入和输出。 文件描述符0&#xff08;stdin&#xff09;&…...

how to write and run .ps1

use .txt filechange the suffix to .ps1 from .txt 3&#xff09;how to run .ps1 3.1) PS D:> .\test.ps1 1 2 3 4 5 6 7 8 9 10 3.2) PS D:> tes then press tab key to compensate and complete the whole file name...

如何在PHP中处理跨域请求?

在 PHP 中处理跨域请求&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;&#xff0c;通常需要在服务器端设置相应的 HTTP 头&#xff0c;以允许来自其他域的请求。以下是一些处理跨域请求的方法&#xff1a; 设置 HTTP 头&#xff1a; 在服务器端&#…...

spring boot 配置多数据源 踩坑 BindingException: Invalid bound statement (not found)

在上一篇&#xff1a;《【已解决】Spring Boot多数据源的时候&#xff0c;mybatis报错提示&#xff1a;Invalid bound statement (not found)》 凯哥(凯哥Java) 已经接受了&#xff0c;在Spring Boot配置多数据源时候&#xff0c;因为自己马虎&#xff0c;导致的一个坑。下面&a…...

【产品】Axure的基本使用(二)

文章目录 一、元件基本介绍1.1 概述1.2 元件操作1.3 热区的使用 二、表单型元件的使用2.1 文本框2.2 文本域2.3 下拉列表2.4 列表框2.5 单选按钮2.6 复选框2.7 菜单与表格元件的使用 三、实例3.1 登录2.2 个人简历 一、元件基本介绍 1.1 概述 在Axure RP中&#xff0c;元件是…...

Python语言学习笔记之十(字符串处理)

本课程对于有其它语言基础的开发人员可以参考和学习&#xff0c;同时也是记录下来&#xff0c;为个人学习使用&#xff0c;文档中有此不当之处&#xff0c;请谅解。 字符串处理&#xff1a;以实现字符串的分割、替换、格式化、大小写转换&#xff0c;Python字符串处理是指对Py…...

WPF-附加属性《十二》

非常重要 依赖属性和附加属性&#xff0c;两者是有关系的&#xff0c;也是有些区别的&#xff0c;很多时候&#xff0c;可能会把两者混淆了。 附加属性&#xff08;Attach Property&#xff09; 顾名思义&#xff0c;就是附加上面的属性&#xff0c;自身是没有的&#xff0c;…...

算法通关第十九关-青铜挑战理解动态规划

大家好我是苏麟 , 今天聊聊动态规划 . 动态规划是最热门、最重要的算法思想之一&#xff0c;在面试中大量出现&#xff0c;而且题目整体都偏难一些对于大部人来说&#xff0c;最大的问题是不知道动态规划到底是怎么回事。很多人看教程等&#xff0c;都被里面的状态子问题、状态…...

2023 GitHub年度排行榜,JEECG上榜第三名,势头依然很猛~

2023 GitHub年度排行榜TOP10&#xff0c;JeecgBoot上榜第三名&#xff0c;势头依然很猛~...

由@EnableWebMvc注解引发的Jackson解析异常

同事合了代码到开发分支&#xff0c;并没有涉及到改动的类却报错。错误信息如下&#xff1a; Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.conv…...

ce从初阶到大牛--函数

1、显示/etc/passwd文件中以bash结尾的行&#xff1b; grep "bash$" /etc/passwd2、找出/etc/passwd文件中的三位或四位数&#xff1b; grep -E \b[0-9]{3,4}\b /etc/passwd3、找出/etc/grub2.cfg文件中&#xff0c;以至少一个空白字符开头&#xff0c;后面又跟了非…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解

文章目录 一、开启慢查询日志&#xff0c;定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程

鸿蒙电脑版操作系统来了&#xff0c;很多小伙伴想体验鸿蒙电脑版操作系统&#xff0c;可惜&#xff0c;鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机&#xff0c;来体验大家心心念念的鸿蒙系统啦&#xff01;注意&#xff1a;虚拟…...

rm视觉学习1-自瞄部分

首先先感谢中南大学的开源&#xff0c;提供了很全面的思路&#xff0c;减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接&#xff1a;https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架&#xff1a; 代码框架结构&#xff1a;readme有…...