Spring Security Core 5.1.2 原始碼解析 -- PasswordEncoderFactories
阿新 • • 發佈:2018-12-12
概述
PasswordEncoderFactories
是Spring Security
建立DelegatingPasswordEncoder
物件的工廠類。該工廠所建立的DelegatingPasswordEncoder
預設使用bcrypt
用於加密,並且能夠用於匹配以下幾種密碼型別 :
- ldap
- MD4
- MD5
- noop (明文密碼)
- pbkdf2
- scrypt
- SHA-1
- SHA-256
- sha256
原始碼解析
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.crypto.factory;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework. security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* Used for creating {@link PasswordEncoder} instances
* @author Rob Winch
* @since 5.0
*/
public class PasswordEncoderFactories {
/**
* 建立 DelegatingPasswordEncoder 例項的工廠方法
* @return the PasswordEncoder to use
*/
@SuppressWarnings("deprecation")
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";// 指定加密密碼要使用的PasswordEncoder
// 將Spring Security提供的所有PasswordEncoder實現都包裝到所建立的DelegatingPasswordEncoder
// 中,當用於匹配密碼時,密碼密文的格式是 : "{encoderId}xxxxxxx",DelegatingPasswordEncoder
// 會解析出密碼中的"encoderId"從下面的encoders中找到相應的PasswordEncoder去檢驗輸入的密碼和
// 密碼密文中的"xxxxxxx"是否匹配
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());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
private PasswordEncoderFactories() {}
}
例子演示該工廠類
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
public class PasswordEncoderFactoriesTest {
public static void main(String[] args) {
// 返回的encoder實現類實際上是 DelegatingPasswordEncoder , 它其實是一個 PasswordEncoder 代理,
// 代理了其他一組 PasswordEncoder
// DelegatingPasswordEncoder 用於密碼匹配的密碼密文必須符合格式 : "{encoderId}xxxxxxx",
// 它所代理的某個 PasswordEncoder 所能接收的密碼密文應該是上面例子密碼中的 "xxxxxxx" 部分
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
{
// 測試1:預設用於加密的是 BCryptPasswordEncoder
System.out.println("測試1:預設用於加密的是 BCryptPasswordEncoder");
final String passwordPlainText = "passw0rdIsTiger";
final String passwordCypher = encoder.encode(passwordPlainText);
System.out.printf("密碼明文是 : %s\n", passwordPlainText);
System.out.printf("密碼密文是 : %s\n", passwordCypher);
final String expectedPrefix = "{bcrypt}";
System.out.printf("密碼密文字首是 %s : %s\n", expectedPrefix, passwordCypher.startsWith(expectedPrefix));
final boolean match = encoder.matches(passwordPlainText, passwordCypher);
System.out.printf("密碼密文和密碼明文匹配 : %s\n", match);
}
{
// 測試2:工廠產生的 PasswordEncoder 會根據密碼密文encoderId字首對應的PasswordEncoder進行密碼匹配
System.out.println("測試2:工廠產生的 PasswordEncoder 會根據密碼密文encoderId字首對應的PasswordEncoder進行密碼匹配");
final String passwordPlainText = "password";
String cypher1 = "{noop}password";
String cypher2 = "{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc";
String cypher3 = "{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=";
String cypher4 = "{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0";
System.out.printf("密碼明文 : %s\n", passwordPlainText);
System.out.printf("密碼密文1 : %s\n", cypher1);
System.out.printf("密碼密文2 : %s\n", cypher2);
System.out.printf("密碼密文3 : %s\n", cypher3);
System.out.printf("密碼密文4 : %s\n", cypher4);
System.out.printf("密碼密文1和密碼明文匹配 : %s\n", encoder.matches(passwordPlainText, cypher1));
System.out.printf("密碼密文2和密碼明文匹配 : %s\n", encoder.matches(passwordPlainText, cypher2));
System.out.printf("密碼密文3和密碼明文匹配 : %s\n", encoder.matches(passwordPlainText, cypher3));
System.out.printf("密碼密文4和密碼明文匹配 : %s\n", encoder.matches(passwordPlainText, cypher4));
}
}
}
該例子程式碼的控制檯輸出
測試1:預設用於加密的是 BCryptPasswordEncoder
密碼明文是 : passw0rdIsTiger
密碼密文是 : {bcrypt}$2a$10$7TVRqzLhYecMy/A03MTHpuwnqmg2yumhxwEc3D3pRoS6CAq9Gbsou
密碼密文字首是 {bcrypt} : true
密碼密文和密碼明文匹配 : true
測試2:工廠產生的 PasswordEncoder 會根據密碼密文encoderId字首對應的PasswordEncoder進行密碼匹配
密碼明文 : password
密碼密文1 : {noop}password
密碼密文2 : {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc
密碼密文3 : {scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
密碼密文4 : {sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
密碼密文1和密碼明文匹配 : true
密碼密文2和密碼明文匹配 : true
密碼密文3和密碼明文匹配 : true
密碼密文4和密碼明文匹配 : true