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

大连网站搜索优温州seo排名公司

大连网站搜索优,温州seo排名公司,重庆网站提示,工信部网站备案修改目录 大纲 一、前言 1. 加密意义 2. 常见方案 2.1. Hash 算法 2.2. 单向自适应函数 二、PasswordEncoder 三、DelegatingPasswordEncoder 1. DelegatingPasswordEncoder源码 2. PasswordEncoderFactories源码 四、如何使用 PasswordEncoder 五、密码加密实战 六、密…

目录

大纲

一、前言

1. 加密意义

2. 常见方案

2.1. Hash 算法

2.2. 单向自适应函数

二、PasswordEncoder

三、DelegatingPasswordEncoder

1. DelegatingPasswordEncoder源码

2. PasswordEncoderFactories源码

四、如何使用 PasswordEncoder

五、密码加密实战

六、密码自动升级


大纲

  • 密码为什么要加密
  • 常见加密的解决方案
  • PasswordEncoder 详解
  • 优雅使用加密

一、前言

1. 加密意义

2011 年12月21 日,有人在网络上公开了一个包含600万个 CSDN 用户资料的数据库,数据全部为明文储

存,包含用户名、密码以及注册邮箱。事件发生后 CSDN 在微博、官方网站等渠道发出了声明,解释说此数据库

系2009 年备份所用,因不明原因泄漏,已经向警方报案,后又在官网发出了公开道歉信。在接下来的十多天里,

金山、网易、京东、当当、新浪等多家公司被卷入到这次事件中。整个事件中最触目惊心的莫过于 CSDN 把用户

密码明文存储,由于很多用户是多个网站共用一个密码,因此一个网站密码泄漏就会造成很大的安全隐患。由于

有了这么多前车之鉴,我们现在做系统时,密码都要加密处理。

在前面的案例中,凡是涉及密码的地方,我们都采用明文存储,在实际项目中这肯定是不可取的,因为这会

带来极高的安全风险。

在企业级应用中,密码不仅需要加密,还需要加盐,最大程度地保证密码安全。

2. 常见方案

2.1. Hash 算法

最早我们使用类似 SHA-256 、SHA-512 、MD5等这样的单向 Hash 算法。用户注册成功后,保存在数据

库中不再是用户的明文密码,而是经过 SHA-256 加密计算的一个字行串,当用户进行登录时,用户输入的明文密

码用 SHA-256 进行加密,加密完成之后,再和存储在数据库中的密码进行比对,进而确定用户登录信息是否有

效。如果系统遭遇攻击,最多也只是存储在数据库中的密文被泄漏。

这样就绝对安全了吗?由于彩虹表这种攻击方式的存在以及随着计算机硬件的发展,每秒执行数十亿次

HASH计算己经变得轻轻松松,

这意味着即使给密码加密加盐也不再安全。

参考: 彩虹表

2.2. 单向自适应函数<Adaptive One-way Functions>

在Spring Security 中,我们现在是用一种自适应单向函数 (Adaptive One-way Functions)来处理密码问

题,这种自适应单向函数在进行密码匹配时,会有意占用大量系统资源(例如CPU、内存等),这样可以增加恶

意用户攻击系统的难度。在Spring Securiy 中,开发者可以通过 bcrypt、PBKDF2、sCrypt 以及 argon2 来体验

这种自适应单向函数加密。由于自适应单向函数有意占用大量系统资源,因此每个登录认证请求都会大大降低应

用程序的性能,但是 Spring Secuity 不会采取任何措施来提高密码验证速度,因为它正是通过这种方式来

增强系统的安全性。

参考 1:用户密码哈希 · libsodium 中文文档

参考 2:https://github.com/xitu/gold-miner/blob/master/TODO1/password-hashing-pbkdf2-scrypt-bcrypt-and-argon2.md

  • BCryptPasswordEncoder
    BCryptPasswordEncoder 使用 bcrypt 算法对密码进行加密,为了提高密码的安全性,bcrypt算法故意降低运行速度,以增强密码破解的难度。同时 BCryptPasswordEncoder “为自己带盐”开发者不需要额外维护一个“盐” 字段,使用 BCryptPasswordEncoder 加密后的字符串就已经“带盐”了,即使相同的明文每次生成的加密字符串都不相同。
  • Argon2PasswordEncoder
    Argon2PasswordEncoder 使用 Argon2 算法对密码进行加密,Argon2 曾在 Password Hashing Competition 竞赛中获胜。为了解决在定制硬件上密码容易被破解的问题,Argon2也是故意降低运算速度,同时需要大量内存,以确保系统的安全性。
  • Pbkdf2PasswordEncoder
    Pbkdf2PasswordEncoder 使用 PBKDF2 算法对密码进行加密,和前面几种类似,PBKDF2
    算法也是一种故意降低运算速度的算法,当需要 FIPS (Federal Information Processing Standard,美国联邦信息处理标准)认证时,PBKDF2 算法是一个很好的选择。
  • SCryptPasswordEncoder
    SCryptPasswordEncoder 使用scrypt 算法对密码进行加密,和前面的几种类似,serypt 也是一种故意降低运算速度的算法,而且需要大量内存。

二、PasswordEncoder

通过对认证流程源码分析得知,实际密码比较是由PasswordEncoder完成的,因此只需要使用

PasswordEncoder 不同实现就可以实现不同方式加密。

public interface PasswordEncoder {String encode(CharSequence rawPassword);boolean matches(CharSequence rawPassword, String encodedPassword);default boolean upgradeEncoding(String encodedPassword) {return false;}
}
  • encode 用来进行明文加密的
  • matches 用来比较密码的方法
  • upgradeEncoding 用来给密码进行升级的方法

默认提供加密算法如下:

三、DelegatingPasswordEncoder

根据上面 PasswordEncoder的介绍,可能会以为 Spring security 中默认的密码加密方案应该是四种自适应

单向加密函数中的一种,其实不然,在 spring Security 5.0之后,默认的密码加密方案其实是

DelegatingPasswordEncoder。

从名字上来看,DelegatingPaswordEncoder 是一个代理类,而并非一种全新的密码加密方案,

DeleggtinePasswordEncoder 主要用来代理上面介绍的不同的密码加密方案。

为什么采DelegatingPasswordEncoder 而不是某一个具体加密方式作为默认的密码加密方案呢?主要考虑了

如下两方面的因素:

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

1. DelegatingPasswordEncoder源码

public class DelegatingPasswordEncoder implements PasswordEncoder {....
}
  • encode 用来进行明文加密的
  • matches 用来比较密码的方法
  • upgradeEncoding 用来给密码进行升级的方法

2. PasswordEncoderFactories源码

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;}@Overridepublic String encode(CharSequence rawPassword) {return getPasswordEncoder().encode(rawPassword);}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return getPasswordEncoder().matches(rawPassword, encodedPassword);}@Overridepublic boolean upgradeEncoding(String encodedPassword) {return getPasswordEncoder().upgradeEncoding(encodedPassword);}private PasswordEncoder getPasswordEncoder() {if (this.passwordEncoder != null) {return this.passwordEncoder;}PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);if (passwordEncoder == null) {passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();}this.passwordEncoder = passwordEncoder;return passwordEncoder;}private <T> T getBeanOrNull(Class<T> type) {try {return this.applicationContext.getBean(type);}catch (NoSuchBeanDefinitionException ex) {return null;}}@Overridepublic String toString() {return getPasswordEncoder().toString();}}

通过源码分析得知如果在工厂中指定了PasswordEncoder,就会使用指定PasswordEncoder,

否则就会使用默认DelegatingPasswordEncoder。

五、密码加密实战

  • 测试生成的密码
 @Test
public void test() {//1.BCryptPasswordEncoderBCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();System.out.println(bCryptPasswordEncoder.encode("123"));//2.Pbkdf2PasswordEncoderPbkdf2PasswordEncoder pbkdf2PasswordEncoder = new Pbkdf2PasswordEncoder();System.out.println(pbkdf2PasswordEncoder.encode("123"));//3.SCryptPasswordEncoder //需要额外引入依赖SCryptPasswordEncoder sCryptPasswordEncoder = new SCryptPasswordEncoder();System.out.println(sCryptPasswordEncoder.encode("123"));//4.Argon2PasswordEncoder //需要额外引入依赖Argon2PasswordEncoder argon2PasswordEncoder = new Argon2PasswordEncoder();System.out.println(argon2PasswordEncoder.encode("123"));
}
  • 使用固定密码加密方案
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder BcryptPasswordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("$2a$10$WGFkRsZC0kzafTKOPcWONeLvNvg2jqd3U09qd5gjJGSHE5b0yoy6a").roles("xxx").build());return inMemoryUserDetailsManager;}
}
  • 使用灵活密码加密方案 推荐
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{bcrypt}$2a$10$WGFkRsZC0kzafTKOPcWONeLvNvg2jqd3U09qd5gjJGSHE5b0yoy6a").roles("xxx").build());return inMemoryUserDetailsManager;}
}

六、密码自动升级

推荐使用DelegatingPasswordEncoder 的另外一个好处就是自动进行密码加密方案的升级,这个功能在整合一些

老的系统时非常有用。

  • 准备库表
-- 用户表
CREATE TABLE `user`
(`id`                    int(11) NOT NULL AUTO_INCREMENT,`username`              varchar(32)  DEFAULT NULL,`password`              varchar(255) DEFAULT NULL,`enabled`               tinyint(1) DEFAULT NULL,`accountNonExpired`     tinyint(1) DEFAULT NULL,`accountNonLocked`      tinyint(1) DEFAULT NULL,`credentialsNonExpired` tinyint(1) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- 角色表
CREATE TABLE `role`
(`id`      int(11) NOT NULL AUTO_INCREMENT,`name`    varchar(32) DEFAULT NULL,`name_zh` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- 用户角色关系表
CREATE TABLE `user_role`
(`id`  int(11) NOT NULL AUTO_INCREMENT,`uid` int(11) DEFAULT NULL,`rid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY   `uid` (`uid`),KEY   `rid` (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
  • 插入数据
-- 插入用户数据
BEGIN;INSERT INTO `user`VALUES (1, 'root', '{noop}123', 1, 1, 1, 1);INSERT INTO `user`VALUES (2, 'admin', '{noop}123', 1, 1, 1, 1);INSERT INTO `user`VALUES (3, 'blr', '{noop}123', 1, 1, 1, 1);
COMMIT;
-- 插入角色数据
BEGIN;INSERT INTO `role`VALUES (1, 'ROLE_product', '商品管理员');INSERT INTO `role`VALUES (2, 'ROLE_admin', '系统管理员');INSERT INTO `role`VALUES (3, 'ROLE_user', '用户管理员');
COMMIT;
-- 插入用户角色数据
BEGIN;INSERT INTO `user_role`VALUES (1, 1, 1);INSERT INTO `user_role`VALUES (2, 1, 2);INSERT INTO `user_role`VALUES (3, 2, 2);INSERT INTO `user_role`VALUES (4, 3, 3);
COMMIT;
  • 整合 mybatis
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version>
</dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?characterEncoding=UTF-88&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.type-aliases-package=com.baizhi.entity
logging.level.com.baizhi.dao=debug
  • 编写实体类
public class User implements UserDetails {private Integer id;private String username;private String password;private Boolean enabled;private Boolean accountNonExpired;private Boolean accountNonLocked;private Boolean credentialsNonExpired;private List<Role> roles = new ArrayList<>();@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<SimpleGrantedAuthority> authorities = new ArrayList<>();for (Role role : roles) {authorities.add(new SimpleGrantedAuthority(role.getName()));}return authorities;}@Overridepublic String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@Overridepublic boolean isAccountNonExpired() {return accountNonExpired;}public void setAccountNonExpired(Boolean accountNonExpired) {this.accountNonExpired = accountNonExpired;}@Overridepublic boolean isAccountNonLocked() {return accountNonLocked;}public void setAccountNonLocked(Boolean accountNonLocked) {this.accountNonLocked = accountNonLocked;}@Overridepublic boolean isCredentialsNonExpired() {return credentialsNonExpired;}public void setCredentialsNonExpired(Boolean credentialsNonExpired) {this.credentialsNonExpired = credentialsNonExpired;}@Overridepublic boolean isEnabled() {return enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}
}
public class Role {private Integer id;private String name;private String nameZh;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNameZh() {return nameZh;}public void setNameZh(String nameZh) {this.nameZh = nameZh;}
}
  • 创建dao
@Mapper
public interface UserDao {List<Role> getRolesByUid(Integer uid);User loadUserByUsername(String username);Integer updatePassword(@Param("username") String username,@Param("password") String password);
}
  • 编写 mapper
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baizhi.dao.UserDao"><select id="loadUserByUsername" resultType="User">select id,username,password,enabled,accountNonExpired,accountNonLocked,credentialsNonExpiredfrom `user`where username = #{username}</select><select id="getRolesByUid" resultType="Role">select r.id,r.name,r.name_zh nameZhfrom `role` r,`user_role` urwhere r.id = ur.ridand ur.uid = #{uid}</select><update id="updatePassword">update `user` set password=#{password}where username=#{username}</update></mapper>
  • 编写service 实现
@Service
public class MyUserDetailService implements UserDetailsService,UserDetailsPasswordService {private final UserDao userDao;@Autowiredpublic MyUserDetailService(UserDao userDao) {this.userDao = userDao;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userDao.loadUserByUsername(username);if (ObjectUtils.isEmpty(user)) {throw new RuntimeException("用户不存在!");}user.setRoles(userDao.getRolesByUid(user.getId()));return user;}@Overridepublic UserDetails updatePassword(UserDetails user, String newPassword) {Integer result = userDao.updatePassword(user.getUsername(), newPassword);if (result == 1) {((User) user).setPassword(newPassword);}return user;}
}
  • 配置securityconfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final MyUserDetailService myUserDetailService;@Autowiredpublic SecurityConfig(MyUserDetailService myUserDetailService) {this.myUserDetailService = myUserDetailService;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//查询数据库auth.userDetailsService(myUserDetailService);}}
  • 启动项目测试
http://www.dtcms.com/wzjs/15942.html

相关文章:

  • 怎么自己做微网站吗如何做品牌营销
  • 南京市建设工程造价管理处网站爱站网关键词查询
  • 建设部网站怎么查岗位人员自制网站
  • 虚拟主机建站最新新闻热点大事件
  • 微信公众号红包网站开发今天的热点新闻
  • 武汉网站建设公司厂家石家庄房价
  • 做垃圾网站怎么上百度推广产品
  • 珠海十大网站建设公司网络营销包括哪些
  • 古镇网站建设深圳网站营销seo费用
  • 做微网站公司简介怎么在网上推广广告
  • 50岁到55岁急招工东莞搜索网络优化
  • 帮公司做网站网站建设的方法有哪些
  • 企业建设网站公司安徽搜索引擎优化
  • 怎么查网站开发者联系方式市场营销毕业后做什么工作
  • 怎样做一名优秀的网站技术客服新东方留学机构官网
  • 成都交投成高建设公司网站手机百度app免费下载
  • 合肥网站建设兼职外贸平台排名
  • 自己建设网站怎么做seo系统源码
  • 曹县有没有做网站seo如何提高网站排名
  • 汕头市政府门户网站官网手机百度网页版 入口
  • 龙岩做网站改版找哪家公司今日头条搜索引擎
  • 个旧网络推广宁波seo网页怎么优化
  • 郑州大学现代远程教育《网页设计与网站建设》课程考核要求网络营销的策划方案
  • 珠海企业网站广州全网推广
  • 服务器如何做网站网站seo
  • 常用网站开发工具千锋教育学费多少
  • 网站怎么做搜素引擎如何在百度上做广告
  • 做风险代理案源的网站网站提交入口百度
  • 网站好坏标准seo关键词查询
  • 网站规划设计是什么淘宝指数查询工具