Spring Security 05 密码加密

news2024/11/24 1:07:44

目录

DelegatingPasswordEncoder

使用 PasswordEncoder

密码加密实战

密码自动升级


实际密码比较是由PasswordEncoder完成的,因此只需要使用PasswordEncoder 不同实现就可以实现不同方式加密。

public interface PasswordEncoder {
    // 进行明文加密
    String encode(CharSequence rawPassword);
​
    // 比较密码
    boolean matches(CharSequence rawPassword, String encodedPassword);
​
    // 密码升级
    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

DelegatingPasswordEncoder

根据上面 PasswordEncoder的介绍,可能会以为 Spring security 中默认的密码加密方案应该是四种自适应单向加密函数中的一种,其实不然,在 spring Security 5.0之后,默认的密码加密方案其实是 DelegatingPasswordEncoder。从名字上来看,DelegatingPaswordEncoder 是一个代理类,而并非一种全新的密码加密方案,DeleggtinePasswordEncoder 主要用来代理上面介绍的不同的密码加密方案。为什么采DelegatingPasswordEncoder 而不是某一个具体加密方式作为默认的密码加密方案呢?主要考虑了如下两方面的因素:

  • 兼容性:使用 DelegatingPasswrordEncoder 可以帮助许多使用旧密码加密方式的系统顺利迁移到 Spring security 中,它允许在同一个系统中同时存在多种不同的密码加密方案。
  • 便捷性:密码存储的最佳方案不可能一直不变,如果使用 DelegatingPasswordEncoder作为默认的密码加密方案,当需要修改加密方案时,只需要修改很小一部分代码就可以实现。

DelegatingPasswordEncoder源码

public class DelegatingPasswordEncoder implements PasswordEncoder {
  ....
}

PasswordEncoderFactories源码

public final class PasswordEncoderFactories {
​
    private PasswordEncoderFactories() {
    }
​
    
    @SuppressWarnings("deprecation")
    public static PasswordEncoder createDelegatingPasswordEncoder() {
        String encodingId = "bcrypt";
        Map<String, PasswordEncoder> encoders = new HashMap<>();
        encoders.put(encodingId, new BCryptPasswordEncoder());
        encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
        encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
        encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
        encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
        encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
        encoders.put("scrypt", new SCryptPasswordEncoder());
        encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
        encoders.put("SHA-256",
                new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
        encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
        encoders.put("argon2", new Argon2PasswordEncoder());
        return new DelegatingPasswordEncoder(encodingId, encoders);
    }
​
}

使用 PasswordEncoder

查看WebSecurityConfigurerAdapter类中源码

static class LazyPasswordEncoder implements PasswordEncoder {
        private ApplicationContext applicationContext;
        private PasswordEncoder passwordEncoder;
​
        LazyPasswordEncoder(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }
​
        public String encode(CharSequence rawPassword) {
            return this.getPasswordEncoder().encode(rawPassword);
        }
​
        public boolean matches(CharSequence rawPassword, String encodedPassword) {
            return this.getPasswordEncoder().matches(rawPassword, encodedPassword);
        }
​
        public boolean upgradeEncoding(String encodedPassword) {
            return this.getPasswordEncoder().upgradeEncoding(encodedPassword);
        }
​
        private PasswordEncoder getPasswordEncoder() {
            if (this.passwordEncoder != null) {
                // 若指定的 passwordEncoder 不为空则使用指定的 passwordEncoder
                return this.passwordEncoder; 
            } else {
                // 使用默认的 DelegatingPasswordEncoder
                PasswordEncoder passwordEncoder = (PasswordEncoder)AuthenticationConfiguration.getBeanOrNull(this.applicationContext, PasswordEncoder.class);
                if (passwordEncoder == null) {
                    passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
                }
​
                this.passwordEncoder = passwordEncoder;
                return passwordEncoder;
            }
        }
​
        public String toString() {
            return this.getPasswordEncoder().toString();
        }
    }

密码加密实战

    @Bean
    public PasswordEncoder BcryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
​
    @Bean
    public UserDetailsService userDetailsService(){
        UserDetails user = User.withUsername("admin").password("$2a$10$WGFkRsZC0kzafTKOPcWONeLvNvg2jqd3U09qd5gjJGSHE5b0yoy6a").roles("ADMIN").build();
        return new InMemoryUserDetailsManager(user);
    }

使用灵活密码加密方案 推荐

    @Bean
    public UserDetailsService userDetailsService(){
        UserDetails user = User.withUsername("admin").password("$2a$10$WGFkRsZC0kzafTKOPcWONeLvNvg2jqd3U09qd5gjJGSHE5b0yoy6a").roles("ADMIN").build();
        return new InMemoryUserDetailsManager(user);
    }

密码自动升级

@Mapper
public interface UserMapper {
​
    //根据用户名查询用户
    User loadUserByUsername(String username);
​
    Integer updatePassword(@Param("username") String username, @Param("password") String password);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yang.mapper.UserMapper">
​
    <update id="updatePassword">
        update `user` set password = #{password}
        where username= #{username}
    </update>
​
    <!--查询单个-->
    <select id="loadUserByUsername" resultType="com.yang.entity.User">
        select id,
               username,
               password,
               enabled,
               accountNonExpired,
               accountNonLocked,
               credentialsNonExpired
        from user
        where username = #{username}
    </select>
​
</mapper>
public interface UserService {
​
    UserDetails loadUserByUsername(String username);
​
    Integer updateUser(String username, String password);
}
@Service
public class UserServiceImpl implements UserService {
​
    private final UserMapper userMapper;
​
    @Autowired
    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
​
    @Override
    public UserDetails loadUserByUsername(String username) {
        User user = userMapper.loadUserByUsername(username);
        if(ObjectUtils.isEmpty(user)){
            throw new RuntimeException("用户不存在");
        }
        user.setRoles(userMapper.getRolesByUid(user.getId()));
        return user;
    }
​
    @Override
    public Integer updateUser(String username, String password) {
        return userMapper.updatePassword(username, password);
    }
}
@Component
public class UserDetailService implements UserDetailsService, UserDetailsPasswordService {
​
    private final UserService userService;
​
    public UserDetailService(UserService userService) {
        this.userService = userService;
    }
​
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userService.loadUserByUsername(username);
    }
​
    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {
        Integer updateRow = userService.updateUser(user.getUsername(), newPassword);
        if (updateRow == 1){
            ((User) user).setPassword(newPassword);
        }
        return user;
    }
}
@Configuration
public class WebSecurityConfig {
​
    private final UserDetailService userDetailService;
​
    public WebSecurityConfig(UserDetailService userDetailService) {
        this.userDetailService = userDetailService;
    }
​
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
​
​
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .mvcMatchers("/index")
                .permitAll()
                .anyRequest().authenticated()
                .and().formLogin()
                .and().userDetailsService(userDetailService); // 自定义数据源
        return http.csrf().disable().build();
    }
}

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

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

相关文章

如何搭建自己的博客网站(手把手教你搭建免费个人博客网站)

没有前言直接开始正文&#xff0c;搭建一个博客需要服务器&#xff0c;域名&#xff0c;博客程序。 博客程序常用的有wordpress&#xff0c;z-blog&#xff0c;typecho等等&#xff0c;其中wordpress和z-blog最为简单&#xff0c;typecho需要一定的技术含量&#xff0c;这里暂…

使用NPOI做Excel简单报表

文章目录 前言初版表格&#xff0c;单元格的合并进阶表格&#xff0c;单元格美化小结 前言 前面介绍了NPOI单元格样式的使用、单元格合并&#xff0c;以及NPOI提供的颜色。现在用上前面的一些知识点&#xff0c;做一个测试结果表格。 1、 介绍NPOI 的颜色卡、名称以及索引 ht…

图片去摩尔纹简述实现python代码示例

这篇文章主要为大家介绍了图片去摩尔纹简述实现的python代码示例&#xff0c;有需要的朋友可以借鉴参考下&#xff0c;希望能够有所帮助&#xff0c;祝大家多多进步&#xff0c;早日升职加薪 1、前言 当感光元件像素的空间频率与影像中条纹的空间频率接近时&#xff0c;可能产生…

分布式系统需要关注的技术点和面试经常问的点

1、分布式系统概述 关于什么是分布式系统&#xff0c;有很多文章介绍&#xff0c;其实这个并不难理解&#xff0c;大白话讲就是&#xff1a;工厂活多了一个人撑不住&#xff0c;那就多找些工人一起干&#xff0c;要让这么多人为了一个目标干得快干得好&#xff0c;就需要一些规…

自主可控智能网联汽车操作系统

开发自主可控智能网联汽车操作系统的必要性 当下&#xff0c;传统汽车操作系统行业的核心技术几乎由国外的黑莓、谷歌、风河、Vector、ETAS等垄断。操作系统已成为我国智能网联汽车发展过程中的关键卡脖子技术&#xff0c;开发自主可控的智能网联汽车操作系统势在必行。 操作…

CVPR 2023 | 达摩院REALY头部重建榜单冠军模型HRN解读

团队模型、论文、博文、直播合集&#xff0c;点击此处浏览 前言 高保真 3D 头部重建在许多场景中都有广泛的应用&#xff0c;例如 AR/VR、医疗、电影制作等。尽管大量的工作已经使用 LightStage 等专业硬件实现了出色的重建效果&#xff0c;从单一或稀疏视角的单目图像估计高精…

微服务架构设计与实践

随着互联网的发展&#xff0c;软件开发已经成为各种企业发展的重要手段。然而&#xff0c;单体应用在长时间的维护中会变得复杂、难以扩展、难以修改。因此&#xff0c;为了满足业务需求&#xff0c;微服务架构应运而生。本篇文章将深入探讨微服务架构的设计与实践。 一、微服务…

C++中的类与对象

类与对象 我们在C语言中自定义的struct 叫做结构体&#xff0c;而在C中我们把struct升级为了类&#xff0c;并且还加入了一个class&#xff0c;也称为类&#xff0c;那么我们今天就来看一下结构体和类的不同和相同 1.结构体与类 我们在C语言中的结构体是struct&#xff0c;而…

QT学习笔记(持续更新)

QT 一、按钮 1.效果 2.代码 #include<QPushButton>//头文件myWidget::myWidget(QWidget *parent): QWidget(parent) {//方法1QPushButton *btnnew QPushButton;//btn->show();//以顶层方式显示btn->setParent(this);//在myWidget窗口中btn->setText("按钮…

JS编程中的API hook

JavaScript奇技淫巧&#xff1a;Hook与反Hook 作者&#xff1a;专注于JS混淆加密的 JShaman API HOOK技术&#xff0c;在PC时代曾盛行&#xff0c;是高端的技术。在JavaScript编程中&#xff0c;也可以应用API Hook技术实现不寻常的效果。 例&#xff0c;eval hook&#xff1a…

Kotlin 基础 笔记

这里写目录标题 变量函数条件语句if/else 语句when 语句if/else 表达式 和 when 表达式 Kotlin 中的null使用 ?: Elvis 运算符 类和对象构造函数类之间的关系可见性修饰符定义属性委托 变量 变量是存储单项数据的容器&#xff0c;必须先声明变量&#xff0c;才可以使用。 常见…

Centos7.5 如何安装Bacula 11.05详细教程

环境: 本地华为桌面云服务器环境 Centos 7.5 Bacula 11.05 问题描述: Centos7.5 如何安装Bacula 解决方案: 一、官网下载Bacula 1.下载Source Files11.0.5 2.先安装C 和 C++ 编译器 root@localhost ~]# yum install -y gcc gcc-c++ 1 已安装: 2 gcc.x86_64 0:…

梦想云图Node.JS服务(2023.4.19)

说明 后台提供梦想Node.JS服务&#xff0c;方便调用控件后台功能&#xff0c;Windows服务程序所在目录:Bin\MxDrawServer\Windows&#xff0c;Linux服务程序所在目录:Bin\Linux\MxDrawServer 启动服务 Windows:进入Bin\MxDrawServer\Windows目录&#xff0c;运行start.bat启动…

redis原理及进化之路

Redis 的主从复制经历了多次演进&#xff0c;本文将从最基本的原理和实现讲起&#xff0c;并层层递进&#xff0c;逐步呈现 Redis 主从复制的演进历史。大家将了解到 Redis 主从复制的原理&#xff0c;以及各个改进版本解决了什么问题&#xff0c;并最终看清 Redis 7.0 主从复制…

vue+uniapp疫苗预约接种系统 微信小程序

统计分析&#xff1a;查看用户&#xff0c;疫苗&#xff0c;订单数量&#xff1b;统计近7日&#xff0c;30日订单趋势 用户管理&#xff1a;查看注册用户信息&#xff0c;及删除&#xff08;数据库mysql) 疫苗管理&#xff1a;疫苗增删改查以及上下架 接种点管理&#xff1a;接…

vue3.0 详细说明+案例 !!!

提示&#xff1a;vue3.0 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;Vuee.js的最新版本。它提供了一系列全新的特性&#xff0c;包括更快的渲染速度、更好的Tree Shaking支持以及更好的TypeScript支持。 最重要的特性…

centos7重启后/etc/rc.local中的脚本没有执行

前阵子自己安装了WMware16、centos7&#xff0c;配置好jdk、mysql、nginx、redis并设置好开机自动启动后&#xff0c;打算将服务也做成自启动&#xff0c;因为之前做过本以为会很顺利&#xff0c;结果整了快两小时&#xff0c;觉得有必要记录下。 之前自己记录的博客&#xff…

Faster RCNN系列5——RoI Pooling与全连接层

Faster RCNN系列&#xff1a; Faster RCNN系列1——Anchor生成过程 Faster RCNN系列2——RPN的真值与预测值概述 Faster RCNN系列3——RPN的真值详解与损失值计算 Faster RCNN系列4——生成Proposal与RoI Faster RCNN系列5——RoI Pooling与全连接层 在RPN网络中&#xff0c;已…

融云出海赋能会干货回顾(二)| 地区、赛道选择和避坑攻略

“出海是这个时代给我们的机遇。”这是很多互联网出海人的心声。关注【融云全球互联网通信云】了解更多 走过跌宕起伏的 15 年出海历程&#xff0c;中国出海人现在面对与此前截然不同的市场环境&#xff0c;很多地区蓝海不再&#xff0c;也有不少赛道变得拥挤。 一体两面&…

交友项目【动态点赞动态喜欢】

目录 1&#xff1a;点赞 1.1&#xff1a;动态点赞 1.1.1&#xff1a;分析&实现 1.2&#xff1a;取消点赞 1.2.1&#xff1a;分析&实现 2&#xff1a;喜欢 2.1&#xff1a;动态喜欢 2.1.1&#xff1a;分析&实现 2.2&#xff1a;取消喜欢 2.2.2&#xff1a…