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

news2024/11/23 2:24:34

文章目录

  • 一、密码处理
    • 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 {

    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

在需要用户信息的地方:

@Controller
public class GetUserWithCustomInterfaceController {
    @Autowired
    private IAuthenticationFacade authenticationFacade;

    @RequestMapping(value = "/username", method = RequestMethod.GET)
    @ResponseBody
    public 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.coloradmin.cn/o/912229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无涯教程-PHP Installation on Windows NT/2000/XP with IIS函数

在Windows Server上运行IIS的PHP的安装比在Unix上简单得多,因为它涉及的是预编译的二进制文件而不是源代码。 如果您打算在Windows上安装PHP,那么这是先决条件列表- 运行中的PHP支持的Web服务器。一个正确安装的PHP支持的数据库,如MySQL或Oracle等。(如果您打算使用的话) PHP…

smiley-http-proxy-servlet 实现springboot 接口反向代理,站点代理,项目鉴权,安全的引入第三方项目服务

背景&#xff1a; 项目初期 和硬件集成&#xff0c;实现了些功能服务&#xff0c;由于是局域网环境&#xff0c;安全问题当时都可以最小化无视。随着对接的服务越来越多&#xff0c;部分功能上云&#xff0c;此时就需要有一种手段可以控制到其他项目/接口的访问权限。 无疑 反向…

硬件解码example

使用方法&#xff1a; ./hw_decode vaapi juren-30s.mp4 juren-30s.mp4 验证播放&#xff1a; ffplay -video_size 1920x1080 -pixel_format yuv420p juren-30s.yuv av_hwdevice_iterate_types(type)如果你填入的参数不对&#xff0c;那么这函数这个函数的作用相当于以下命令&…

飞天使-k8s基础组件分析-pod

文章目录 pod介绍pod 生命周期init 容器容器handlerpod中容器共享进程空间sidecar 容器共享 参考链接 pod介绍 最小的容器单元 为啥需要pod? 答: 多个进程丢一个容器里&#xff0c;会因为容器里个别进程出问题而出现蝴蝶效应&#xff0c;pod 是更高级的处理方式pod 如何共享相…

简述docker映射(Mapping)和挂载(Mounting)

映射的概念&#xff1a; 将容器内的端口映射到主机的端口上&#xff0c;这样就可以通过主机的网络接口与容器内部进行通信。主机上对应端口的请求会被转发到容器内部&#xff0c;从而实现对容器内部程序的通信访问&#xff08;注意&#xff01;这里提到的容器内部的端口并不一定…

网络安全(黑客)了解学习路线

谈起黑客&#xff0c;可能各位都会想到&#xff1a;盗号&#xff0c;其实不尽然&#xff1b;黑客是一群喜爱研究技术的群体&#xff0c;在黑客圈中&#xff0c;一般分为三大圈&#xff1a;娱乐圈 技术圈 职业圈。 娱乐圈&#xff1a;主要是初中生和高中生较多&#xff0c;玩网恋…

EasyImage简单图床 - 快速搭建私人图床云盘同时远程访问【无公网IP内网穿透】

憧憬blog主页 在强者的眼中&#xff0c;没有最好&#xff0c;只有更好。我们是移动开发领域的优质创作者&#xff0c;同时也是阿里云专家博主。 ✨ 关注我们的主页&#xff0c;探索iOS开发的无限可能&#xff01; &#x1f525;我们与您分享最新的技术洞察和实战经验&#xff0…

阿里云CDN加速器基本概念与购买开通

文章目录 1.CDN加速器的基本概念1.1.CDN加速器基本介绍1.2.网站引入CDN加速器的架构图1.3.CDN加速器的工作原理1.4.引入CDN后域名解析变成了CNAME&#xff1f; 2.开通阿里云CDN加速服务 1.CDN加速器的基本概念 CDN加速器官方文档&#xff1a;https://help.aliyun.com/product/…

USB音频芯片SSS1700 鑫创优势替代CM6533参考设计|SSS1700规格24bit 96KHZ |替换CM6533方案

Cmedia CM6533是一款US B音频编解码器&#xff0c;内部嵌入8051内核&#xff0c;适用于耳麦&#xff0c;移动娱乐设备直插移动音箱&#xff08;docking&#xff09;&#xff0c;US B音箱&#xff0c;US B麦克风等应用。通过内部8051可以研发出各种应用&#xff0c;例如微软语音…

vue3 pdf、word等文件下载

效果&#xff1a; <div class"byLawBox"><div class"titleBox">规章制度公示</div><div class"contentBox"><TableList:loading"byLawloading"ref"byLawtablistRef":hasImport"false"…

Unity - 特殊文件夹

地址记录&#xff1a;https://www.cnblogs.com/zouqiang/p/6841399.html Assets Assets文件夹是unity项目中放置游戏资源的主文件夹。 该文件夹中的内容将直接反应在编辑器的Project视口中。许多系统API基于该文件夹路径。 Resources Unity允许你按需动态加载游戏资源到场景中…

ubuntu 对多CPU统一设置高性能模式

一、问题描述 之前在网上找到的CPU设置高性能模式&#xff0c;只能设置CPU0单个CPU&#xff0c;下述是对多核CPU统一设置工作模式。 二、软件安装与设置 执行下述命令sudo apt-get install indicator-cpufreq,然后重启电脑。此时&#xff0c;界面右上角会出现如下图标&#xf…

爬虫异常捕获与处理方法详解

Hey&#xff01;作为一名专业的爬虫代理供应商&#xff0c;我今天要和大家分享一些关于爬虫异常捕获与处理的方法。在进行爬虫操作时&#xff0c;我们经常会遇到各种异常情况&#xff0c;例如网络连接错误、请求超时、数据解析错误等等。这些异常情况可能会导致程序崩溃或数据丢…

威班8.19PMP考试爱心送考再出发,能量补给站为学员提供考试保障

8月19日&#xff0c;2023年的第三场PMP考试准时开考。 对于准备了个把月的学员们来说&#xff0c;这一时刻无比重要&#xff0c;为了给威班的PMP学员们考试加油打气&#xff0c;威班特地组织了送考活动&#xff0c;在考场外提前布置应援点&#xff0c;给前去参加考试的学员们带…

5.1 汇编语言:汇编语言概述

汇编语言是一种面向机器的低级语言&#xff0c;用于编写计算机程序。汇编语言与计算机机器语言非常接近&#xff0c;汇编语言程序可以使用符号、助记符等来代替机器语言的二进制码&#xff0c;但最终会被汇编器编译成计算机可执行的机器码。 相较于高级语言&#xff08;如C、P…

紧跟老板思维,这款数据可视化工具神了

在今时今日&#xff0c;依靠大数据可视化分析工具做出一张形象直观、符合企业审美的数据可视化分析报表都不是什么难事&#xff0c;难就难在于做出一张能够紧随老板思维变化展开可视化分析的数据可视化分析报表。接下来要介绍的这款数据可视化工具就是这么一款神奇的BI工具&…

整理文件轻松搞定,教你如何将文件夹里的文件进行类型归类保存

大家好&#xff01;相信大家在日常工作和学习中都会面临着大量的文件管理问题&#xff0c;如何高效地整理和保存文件成为了一大难题。幸运的是&#xff0c;不仅可以帮助你高效整理文件&#xff0c;还能实现文件的类型归类保存。 首先&#xff0c;我们要进入文件批量查询高手主…

七夕给TA满分宠爱!浪漫攻略为约会加分

浪漫的七夕将至&#xff0c;无论是异地恋人还是约会情侣&#xff0c;怎么能缺少节日仪式感~精心策划的约会计划&#xff0c;让浪漫“超级加倍”。 美好的二人世界&#xff0c;共度甜蜜时光&#xff0c;当然需要提前做好攻略&#xff0c;风和日丽的好天气能为约会加分不少。在规…

分享书架二维码 = 分享了10多本电子书

铁子们&#xff01;告诉你一个实用的方法&#xff0c;分享一个书架就等于分享了10多本电子书&#xff0c;不用再一本一本的发送给客户啦&#xff01; 方法如下&#xff1a; 1.首先打开FLBOOK电子杂志制作平台 2.我们开始上传自己的作品&#xff0c;选择PDF上传 3.进入编辑页面…

Python-主线程控制子线程结束-2

需求&#xff1a;主线程创建工作子线程和键盘输入监听子线程。 当用户输入 0 后&#xff0c; 工作子线程会收到停止信号并退出&#xff0c;此时键盘输入监听线程仍然运行&#xff1b; 当用户输入 1 后&#xff0c;会建立新的工作子线程&#xff1b; …