资讯专栏INFORMATION COLUMN

Spring Security 进阶-加密篇

wanglu1209 / 860人阅读

摘要:在中加密是一个很简单却又不能忽略的模块,数据只有加密起来才更安全,这样就散算据库密码泄漏也都是密文。当然也可以自定义构造方法,来制定用其他的方案进行加密。应用先示范下使用系统的来演示下简单的注入构造加密方案

在 Spring Security 中加密是一个很简单却又不能忽略的模块,数据只有加密起来才更安全,这样就散算据库密码泄漏也都是密文。本文分析对应的版本是 5.14。
概念

Spring Security 为我们提供了一套加密规则和密码比对规则,org.springframework.security.crypto.password.PasswordEncoder 接口,该接口里面定义了三个方法。

public interface PasswordEncoder {

    //加密(外面调用一般在注册的时候加密前端传过来的密码保存进数据库)
    String encode(CharSequence rawPassword);

    //加密前后对比(一般用来比对前端提交过来的密码和数据库存储密码, 也就是明文和密文的对比)
    boolean matches(CharSequence rawPassword, String encodedPassword);

    //是否需要再次进行编码, 默认不需要
    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}
该接口实现类有下面这几个

其中常用到的分别有下面这么几个

BCryptPasswordEncoder:Spring Security 推荐使用的,使用BCrypt强哈希方法来加密。

MessageDigestPasswordEncoder:用作传统的加密方式加密(支持 MD5、SHA-1、SHA-256...)

DelegatingPasswordEncoder:最常用的,根据加密类型id进行不同方式的加密,兼容性强

NoOpPasswordEncoder:明文, 不做加密

其他

使用示例 MessageDigestPasswordEncoder

构造的时候需要传入算法字符串,例如 "MD5"、"SHA-1"、"SHA-256"...

String password = "123";

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder("MD5");
String encode = encoder.encode(password);
System.out.println(encode);
System.out.println(encoder.matches(password,encode) == true ? "相等" : "不相等");

输出

{EUjIxnT/OVlk5J54s3LaJRuQgwTchm1gduFHTqI0qjo=}4b40375c57c285cc56c7048bb114db23
相等

调用 encode(..) 加密方法每次都会随机生成盐值,所以对相同的明文进行多次加密,每次结果也是不一样的。
从上面输出部分结合源码可以的出:加密的最终结果分为两部分,盐值 + MD5(password+盐值),调用 matches(..) 方法的时候先从密文中得到盐值,用该盐值加密明文和最终密文作对比。

BCryptPasswordEncoder

构造的时候可以传入哈希强度(strength),强度越大计算量就越大,也就意味着越安全,strength 取值区间[4-31],系统默认是10。

String password = "123";

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encode = encoder.encode(password);
System.out.println(encode);
System.out.println(encoder.matches(password, encode) == true ? "相等" : "不相等");

输出

$2a$10$lxPfE.Zvat6tejB8Q1QGYu3M9lXUUpiWFYzboeyK64kbfgN9v7iBq
相等

调用 encode(..) 方法加密跟上面一样,每次都会随机生成盐值,密文也分为两部分,盐值和最终加密的结果,最终对比的时候从密文里面拿出盐值对明文进行加密,比较最终加密后的结果。

DelegatingPasswordEncoder

这是 Spring Security 推出的一套兼容方案,根据加密类型id字符串(idForEncode)去自身缓存的所有加密方式中(idToPasswordEncoder)取出对应的加密方案对象对明文进行加密和对应密文的对比,只是其密文前面都加上了加密方案id的字符串,具体的咱们看下面代码演示。

其初始化 Spring Security 提供了一个工厂构造方法

public class PasswordEncoderFactories {

    @SuppressWarnings("deprecation")
    public static PasswordEncoder createDelegatingPasswordEncoder() {
        String encodingId = "bcrypt";
        Map 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());

        return new DelegatingPasswordEncoder(encodingId, encoders);
    }
}

这个工厂的静态构造方法把常用的几种方案都注入到缓存中,但是注入的 idForEncode 对应的却是 BCryptPasswordEncoder,这样系统就可以达到在新存储密码可以使用 BCryptPasswordEncoder 加密方案进行加密,但是对于数据库里面以前用其他方式加密的密码也支持比对。

String password = "123";

PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
String encode = encoder.encode(password);
System.out.println(encode);
System.out.println(encoder.matches(password, encode) == true ? "相等" : "不相等");

输出

{bcrypt}$2a$10$Bh23zGZ2YPOsORNexoowb.fX4QH18GEh13eVtZUZvbe2Blx0jIVna
相等

从结果中可以看出,相比原始的 BCryptPasswordEncoder 密文前面多了加密方式的id。

当然也可以自定义构造方法,来制定 DelegatingPasswordEncoder 用其他的方案进行加密。

接下来我们将其指定使用 MD5 方式来加密密码看看结果

Map encoders = new HashMap<>();
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
DelegatingPasswordEncoder encoder = new DelegatingPasswordEncoder("MD5", encoders);
String encode = encoder.encode(password);
System.out.println(encode);
System.out.println(encoder.matches(password, encode) == true ? "相等" : "不相等");

输出

{MD5}{XYwuzP8/lL/a3ASzA9UVM4rFs8lbsLvEoa5ydKER844=}d7f919bfd94554150f8ab3a809209ee3
相等

相比原始的 MessageDigestPasswordEncoder也是密文前面多了加密方式的id。

应用

先示范下使用系统的 UserDetailsManager 来演示下简单的注入

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("liuchao")
                    .password("{bcrypt}$2a$10$S.hMD3oV60YRIj38lHRhP.e3DAu3OwmssE/u/p2GLqqZ3SVsZA77W")
                    .roles("admin","user")
                    .and()
                .passwordEncoder(passwordEncoder);
    }

    @Bean(value = "passwordEncoder")
    public PasswordEncoder delegatingPasswordEncoder() {
        //构造 DelegatingPasswordEncoder 加密方案
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Autowired
    private PasswordEncoder passwordEncoder;
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73868.html

相关文章

  • Spring Security 进阶-原理

    摘要:过滤器基本都是通过过滤器来完成配置的身份认证权限认证以及登出。密码比对通过进行密码比对注可自定义通过获取通过获取生成身份认证通过后最终返回的记录认证的身份信息 知彼知己方能百战百胜,用 Spring Security 来满足我们的需求最好了解其原理,这样才能随意拓展,本篇文章主要记录 Spring Security 的基本运行流程。 过滤器 Spring Security 基本都是通过...

    android_c 评论0 收藏0
  • Spring Security 进阶-细节总结

    摘要:但是我们最好不要在里面对他进行处理,而是放到配置的权限异常来处理。记得配置登录认证前和过程中的一些请求不需要身份认证。登录认证失败不能直接抛出错误,需要向前端响应异常。 关于 Spring Security 的学习已经告一段落了,刚开始接触该安全框架感觉很迷茫,总觉得没有 Shiro 灵活,到后来的深入学习和探究才发现它非常强大。简单快速集成,基本不用写任何代码,拓展起来也非常灵活和强...

    LinkedME2016 评论0 收藏0
  • Spring Security

    摘要:框架具有轻便,开源的优点,所以本译见构建用户管理微服务五使用令牌和来实现身份验证往期译见系列文章在账号分享中持续连载,敬请查看在往期译见系列的文章中,我们已经建立了业务逻辑数据访问层和前端控制器但是忽略了对身份进行验证。 重拾后端之Spring Boot(四):使用JWT和Spring Security保护REST API 重拾后端之Spring Boot(一):REST API的搭建...

    keelii 评论0 收藏0
  • Spring Cloud 参考文档(Spring Cloud Config Server)

    摘要:,这是标记配置文件集版本化的服务器端特性。要配置对称密钥,需要将设置为秘密字符串或使用环境变量将其排除在纯文本配置文件之外。 Spring Cloud Config Server Spring Cloud Config Server为外部配置提供基于HTTP资源的API(名称—值对或等效的YAML内容),通过使用@EnableConfigServer注解,服务器可嵌入Spring Bo...

    harryhappy 评论0 收藏0
  • 你和阿里资深架构师之间,差的不仅仅是年龄(进阶必看)

    摘要:导读阅读本文需要有足够的时间,笔者会由浅到深带你一步一步了解一个资深架构师所要掌握的各类知识点,你也可以按照文章中所列的知识体系对比自身,对自己进行查漏补缺,觉得本文对你有帮助的话,可以点赞关注一下。目录一基础篇二进阶篇三高级篇四架构篇五扩 导读:阅读本文需要有足够的时间,笔者会由浅到深带你一步一步了解一个资深架构师所要掌握的各类知识点,你也可以按照文章中所列的知识体系对比自身,对自己...

    huaixiaoz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<