【SpringSecurity】二、密码处理与获取当前登录用户

文章目录

  • 一、密码处理
    • 1、加密方案
    • 2、BCryptPasswordEncoder类初体验
    • 3、使用加密码加密
  • 二、获取当前登录用户
    • 1、方式一:通过安全上下文的静态调用
    • 2、方式二:做为Controller中方法的参数
    • 3、方式三:从HTTPServletRequest中获取
    • 4、方式四:使用@AuthenticationPrincipal
    • 5、方法五:通过自定义接口获取用户信息
    • 6、在JSP中获取用户信息
    • 7、结果分析

一、密码处理

1、加密方案

密码加密一般使用散列函数,又称散列算法,哈希函数,这些函数都是单向函数(从明文到密文,反之不行),此时哪怕被拖库,拿到密文也无法解析。校验登录时,拿用户的输入进行加密后和库中密文对比即可。

常用的散列算法有MD5和SHA。Spring Security提供多种密码加密方案,基本上都实现了PasswordEncoder接口,官方推荐使用BCryptPasswordEncoder

在这里插入图片描述

接口中,encode方法用来加密,match则用来判断密码的密文是否匹配。

2、BCryptPasswordEncoder类初体验

在这里插入图片描述

可以看到,同样的String密码,三次编码的结果并不相同,如果不添加噪音(加盐),一个字符串被编码后的结果始终相同,则即使它不能反编译,也可以被破解。(反复正向编译不同密码,直到匹配这个密文 ⇒ RainbowCrack彩虹表攻击

@Slf4j
public class PasswordEncoderTest {@Test@DisplayName("测试加密类BCryptPasswordEncoder")  //DisplayName :为测试类或者测试方法设置展示名称void testPassword(){BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();//加密(明文到密文)String encode1 = bCryptPasswordEncoder.encode("123456");log.info("encode1:"+encode1);String encode2 = bCryptPasswordEncoder.encode("123456");log.info("encode2:"+encode2);String encode3 = bCryptPasswordEncoder.encode("123456");log.info("encode3:"+encode3);//匹配方法,判断明文经过加密后是否和密文一样boolean result1 = bCryptPasswordEncoder.matches("123456", encode1);boolean result2 = bCryptPasswordEncoder.matches("123456", encode1);boolean result3 = bCryptPasswordEncoder.matches("123456", encode1);log.info(result1+":"+result2+":"+result3);assertTrue(result1);assertTrue(result2);assertTrue(result3);}
}

查看控制台发现特点是:

相同的字符串加密之后的结果都不一样,但是比较的时候是一样的,因为加了盐(salt)了。

小Tip:

在这里插入图片描述

3、使用加密码加密

接下来,修改编码器为BCryptPasswordEncoder:

@Bean
public PasswordEncoder passwordEncoder(){//使用加密算法对密码进行加密return new BCryptPasswordEncoder();
}

重启服务,发现登录失败,这是因为前端传了密码为123,然后转为密文后,和存于内存中的明文密码123做对比,密文肯定不等于明文,校验失败。因此,系统中定义的用户密码也需要加密,使用密文存储:

* 使用PasswordEncoder接口中的encode方法UserDetails user1 = User.builder().username("liu").password(passwordEncoder().encode("123")).roles("student").build();
UserDetails user2 = User.builder().username("Mr.liu").password(passwordEncoder().encode("123")).roles("teacher").build();

二、获取当前登录用户

根据SpringSecuriuty框架校验用户的流程,可以分析出,想拿当前登录用户的信息,有以下几种方式:

1、方式一:通过安全上下文的静态调用

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();

做个改进,在获取前,首先检查是否存在经过身份验证的用户。

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof AnonymousAuthenticationToken)) {String currentUserName = authentication.getName();return currentUserName;
}

2、方式二:做为Controller中方法的参数

可以直接将principal对象定义为方法参数,框架会正确解析并赋值:

@RestController
public class SecurityTestController {@GetMapping(value = "/username")public String yourMethodName(Principal principal) {//...String userName =  principal.getName();//...}
}

也可直接将Authentication对象定义为Controller中方法的参数:(Authentication接口继承自Principal)

@RestController
public class SecurityTestController {@GetMapping(value = "/username")public String yourMethodName(Authentication authentication) {//...String userName =  authentication.getName();//...}
}

框架为了尽可能的灵活,Authentication 类的API很方便使用。因此,通过转换可以返回principal对象。

UserDetails userDetails = (UserDetails) authentication.getPrincipal();
System.out.println("User has authorities: " + userDetails.getAuthorities());

3、方式三:从HTTPServletRequest中获取

@RestController
public class GetUserWithHTTPServletRequestController {@GetMapping(value = "/username")public String currentUserNameSimple(HttpServletRequest request) {Principal principal = request.getUserPrincipal();String username =  principal.getName();//...}
}

4、方式四:使用@AuthenticationPrincipal

@RestController
public class SecurityController {@GetMapping("/user")public String getUser(@AuthenticationPrincipal UserDetails userDetails) {return "User Name: " + userDetails.getUsername();}
}

@AuthenticationPrincipal注解将会自动提供当前经过身份验证的用户的主体注入到方法中

5、方法五:通过自定义接口获取用户信息

public interface IAuthenticationFacade {Authentication getAuthentication();
}

实现这个自定义接口:

@Component
public class AuthenticationFacade implements IAuthenticationFacade {@Overridepublic Authentication getAuthentication() {return SecurityContextHolder.getContext().getAuthentication();}
}

在需要用户信息的地方:

@Controller
public class GetUserWithCustomInterfaceController {@Autowiredprivate IAuthenticationFacade authenticationFacade;@RequestMapping(value = "/username", method = RequestMethod.GET)@ResponseBodypublic String currentUserNameSimple() {Authentication authentication = authenticationFacade.getAuthentication();return authentication.getName();}
}

以上暴露了Authentication认证对象,且隐藏静态访问代码,让业务解耦并方便测试

6、在JSP中获取用户信息

当前认证用户也可以在jsp页面中获取到。利用spring security标签支持。首先我们需要在页面中定义标签:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

然后,我们可以引用principal:

<security:authorize access="isAuthenticated()">authenticated as <security:authentication property="principal.username" /> 
</security:authorize>

官方文档:https://www.baeldung.com/get-user-in-spring-security

7、结果分析

{"authorities": [{"authority": "ROLE_teacher"}],"details": {"remoteAddress": "0:0:0:0:0:0:0:1","sessionId": "34E452050095348E6306CF95B2025CD9"},"authenticated": true,"principal": {"password": null,"username": "thomas","authorities": [{"authority": "ROLE_teacher"}],"accountNonExpired": true,"accountNonLocked": true,"credentialsNonExpired": true,"enabled": true},"credentials": null,"name": "liu"
}
  • Principal:定义认证的用户,如果用户使用用户名密码登录,principal通常就是一个UserDetails
  • Credentials:登录凭证,一般就是指密码。当用户登录成功之后,登录凭证会被自动擦除,以防止泄露
  • authorities:用户被授予的权限信息,为ROLE_ + “角色”

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

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

相关文章

vim 常见操作

Vim 工作模式 1、vim 三种基本的工作模式 vim有三种基本的工作模式&#xff0c;分别为&#xff1a;命令模式、末行模式、编辑模式。关于这三种工作模式的介绍&#xff0c;请见下文。 1.1、命令模式 使用vim打开文件之后&#xff0c;首先进入命令模式&#xff0c;它是vim编辑…

一文学会使用ChatGPT API搭建自己的聊天网站

一文读懂如何搭建自己的ChatGPT聊天网站 在数字时代的浪潮下&#xff0c;人工智能正变得愈发令人惊叹和亲近。ChatGPT&#xff0c;就是这个变革的杰出代表。这项令人兴奋的技术将强大的自然语言处理能力带到您的指尖&#xff0c;让您能够以前所未有的方式与计算机进行互动。 …

【Redis从头学-8】Redis中的ZSet数据类型实战场景之用户积分榜

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Re…

回流焊炉温曲线图讲解

从下面回流焊炉温曲线标准图分析回流焊的原理&#xff1a; 当PCB进入升温区&#xff08;干燥区&#xff09;时&#xff0c;焊锡膏中的溶剂、气体蒸发掉&#xff0c;同时焊锡膏中的助焊剂润湿焊盘、元器件端头和引脚&#xff0c;焊锡膏软化、塌落、覆盖了焊盘&#xff0c;将焊盘…

部署FTP服务(二)

目录 2.访问FTP服务 1.使用ftp命令行工具 2.使用浏览器 3.使用FileZilla Client 3.Serv-U 1.定义新域 2.创建用户 4. windowsserver搭建ftp服务器 一、FTP工具 二、Windows资源管理器 三、IE浏览器访问 2.访问FTP服务 下面在一台装有Windows10操作系统的计算机中&#…

长胜证券:九成注册制公司选择上市标准一,牛股“双高”特征明显

新股注册制施行以来&#xff0c;新股公司可选的上市规范愈加多样化&#xff0c;不同板块、不同上市规范的新股公司亦呈现出不同特征&#xff0c;新股上市后不再呈现“套路化”的上涨行情&#xff0c;新股破发成为常态。数据显现&#xff0c;2022年全年及2023年以来&#xff0c;…

中小企业精细化仓库管理,WMS仓储管理系统必不可少

尽管传统中小企业的仓库管理并不需要建立大型全自动立体智能仓库&#xff0c;但为了确保企业运营的稳定性和后备支持&#xff0c;它们仍然需要在管理方面制定更多的标准和规范。而为了达到这些目标&#xff0c;WMS仓储管理系统解决方案是必不可少的。 中小企业WMS仓储管理系统…

SpringBoot 模板模式实现优惠券逻辑

一、计算逻辑的类结构图 在这张图里&#xff0c;顶层接口 RuleTemplate 定义了 calculate 方法&#xff0c;抽象模板类 AbstractRuleTemplate 将通用的模板计算逻辑在 calculate 方法中实现&#xff0c;同时它还定义了一个抽象方法 calculateNewPrice 作为子类的扩展点。各个具…

适合国内用户的五款ChatGPT插件

众所周知使用ChatGPT3.5需要使用魔法且不稳定&#xff0c;订阅ChatGPT4.0每月需要支付20美元&#xff0c;并且使用次数有限制。对于那些不想每年花费240美元&#xff08;超过1500元人民币&#xff09;来使用GPT4.0的朋友们来说&#xff0c;还有别的办法吗&#xff1f; 答案是&…

【C语言】位段,枚举和联合体详解

目录 1.位段 1.1 什么是位段 1.2 位段的内存分配 1.3 位段的跨平台问题 2.枚举 2.1 枚举类型的定义 2.2 枚举的优点 3. 联合&#xff08;共用体&#xff09; 3.1 联合类型的定义 3.2 联合的特点 3.3 联合大小的计算 1.位段 1.1 什么是位段 位段的声明和结构体是类…

多线程——学习笔记 1

目录 多线程的了解多线程并行和并发的区别Java程序运行原理多线程程序实现的方式1.继承Thread2.实现Runnable 多线程(实现Runnable的原理&#xff09;实现多线程两种方式的区别匿名内部类实现线程的两种方式获取线程名字和设置名字获取当前线程的对象——hread.currentThread()…

Docker拉取并配置Grafana

Linux下安装Docker请参考&#xff1a;Linux安装Docker 安装准备 新建挂载目录 /opt/grafana/data目录&#xff0c;准备用来挂载放置grafana的数据 /opt/grafana/plugins目录&#xff0c;准备用来放置grafana的插件 /opt/grafana/config目录&#xff0c;准备用来挂载放置graf…

取模运算符在数组下标的应用

什么是取模运算符%&#xff1f; 定义&#xff1a; a mod b&#xff0c;设a、b属于正整数且b>0&#xff0c;如果q、r属于正整数满足aq*br&#xff0c;且0≤r<b&#xff0c;则定义&#xff1a; a mod b r 注意&#xff1a;取模运算符两侧的除数和被除数都是整数&#xff…

Debootstrap 教程

文章目录 Debootstrap 教程安装 debootstrap使用 debootstrap运行 debootstrap进入新的系统结束语 Debootstrap 教程 debootstrap 是一个用于在 Debian-based 系统上创建一个基本的 Debian 系统的工具。它可以用于创建 chroot 环境、容器或者为新的系统安装做准备。 安装 deb…

分布式数据库架构:高可用、高性能的数据存储

在现代信息时代&#xff0c;数据是企业发展的核心。为了支持海量数据的存储、高并发访问以及保证数据的可靠性&#xff0c;分布式数据库架构应运而生。分布式数据库架构是一种将数据存储在多个物理节点上&#xff0c;并通过一系列复杂的协调和管理机制来提供高可用性和高性能的…

Qt下拉菜单

1&#xff0c;QComboBox 2&#xff0c;setMenu()---设置下拉菜单 AI对话未来丨智能写作对话: setMenu()是QWidget类的一个成员函数&#xff0c;在Qt中用于将一个菜单作为一个控件的下拉菜单设置。具体来说&#xff0c;它会把相应的菜单对象与该控件关联&#xff0c;并在控件上…

Element通过v-for循环渲染的form表单校验

需求&#xff1a;有个表单信息是v-for渲染的&#xff0c;例如下图&#xff0c;通过循环遍历实现新增和删除模块&#xff0c;按照平时的写法实现校验&#xff0c;是不能实现我们想要的效果&#xff0c;根据这个需求&#xff0c;我找到了一个解决方法 1.HTML <el-form ref&qu…

ESD门禁管理系统的主要功能和优势

ESD门禁管理系统是一种用于控制和管理人员进出特定区域的系统。它通常由门禁控制器、门禁读卡器、门禁管理软件等组成。 ESD门禁管理系统的主要功能包括&#xff1a; 1. 门禁控制&#xff1a;通过门禁控制器实现对门禁设备的控制&#xff0c;如开关门、锁定门等。 2. 门禁验…

Go与Rust的对比与分析

Rust 和 Go 是两种现代语言&#xff0c;近年来获得了巨大的关注&#xff0c;每种语言都有自己独特的优势和权衡。在这篇文章中&#xff0c;我们将深入探讨 Rust 和 Go 之间的差异&#xff0c;重点关注性能、语言功能和其他关键因素&#xff0c;以帮助您针对您的开发需求做出明智…

【面试】项目经理面试题

文章目录 一、项目管理面试中通常会问到的问题1.项目管理软件工具知识2.做项目计划的技能3.人员管理技能4.沟通技巧5.方法论知识 二、问面试官的问题三. 面试系列推荐 一、项目管理面试中通常会问到的问题 1.项目管理软件工具知识 问题 1: 工期和工作量之间的差异是什么? 答案…