一、認證組件 簡介: 登錄認證的限制 認證組件是drf框架給我們提供的認證介面,它能夠在請求進入視圖函數/類前進驗證(例如:認證用戶是否登錄),對不符合認證的請求進行攔截並返回校驗失敗的信息 (1)、登錄介面 # 認證是基於登錄的介面上面操作的 所以前戲編寫一個簡單的登錄介面 models.py c ...
接下來幾個章節,將逐個介紹身份驗證流程中主要介面
介面 | 描述 |
---|---|
UserDetails | 代表SpringSecurity所看到的用戶 |
GrantedAuthority | 定義應用程式目的範圍內允許用戶執行的操作(讀、寫、刪除等) |
UserDetailsService | 表示用於按用戶名檢索用戶詳細信息的對象 |
UserDetailsManager | 一個較為特殊的UserDetailsService介面。除了按用戶名檢索用戶外,它還可以用於更改用戶集合或特定用戶 |
PasswordEncoder | 指定如何對密碼進行加密或哈希化,以及檢查給定的已編碼字元串是由與明文密碼匹配 |
本文將一起學習相對獨立的PasswordEncoder。
一、先看看定義
package org.springframework.security.crypto.password;
/**
* Service interface for encoding passwords.
*
* The preferred implementation is {@code BCryptPasswordEncoder}.
*
* @author Keith Donald
*/
public interface PasswordEncoder {
/**
* Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or
* greater hash combined with an 8-byte or greater randomly generated salt.
*/
String encode(CharSequence rawPassword);
/**
* Verify the encoded password obtained from storage matches the submitted raw
* password after it too is encoded. Returns true if the passwords match, false if
* they do not. The stored password itself is never decoded.
* @param rawPassword the raw password to encode and match
* @param encodedPassword the encoded password from storage to compare with
* @return true if the raw password, after encoding, matches the encoded password from
* storage
*/
boolean matches(CharSequence rawPassword, String encodedPassword);
/**
* Returns true if the encoded password should be encoded again for better security,
* else false. The default implementation always returns false.
* @param encodedPassword the encoded password to check
* @return true if the encoded password should be encoded again for better security,
* else false.
*/
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
該介面定義了兩個抽象方法,其中幾個具有預設實現。在處理PasswordEncoder實現時,最常見的是抽象的encode()和matches()方法。
encode(CharSequence rawPassword)方法的目的是返回所提供字元串的轉換。就SpringSecurity功能而言,它用於為指定密碼提供加密或哈希化。
之後可以使用matches(CharSequence rawPassword, String encodedPassword)方法檢查已編碼的字元串是否與演示密碼匹配。可以在身份驗證過程中使用matches()方法根據一組已知憑據來檢驗所提供的的密碼。
第三個方法被稱為upgradeEncoding(String encodedPassword),在介面中預設設置為false。如果重寫它以返回true,那麼為了更好的安全性,將重新對已編碼的密碼進行編碼(不推薦這種方式)。
二、介面的作用
一般而言,系統並不以明文形式管理密碼,因此密碼通常要經過某種轉換,這使得讀取和竊取密碼變得較為困難。為此,SpringSecurity定義了一個單獨的介面。
實現這個介面是為了告知SpringSecurity如何驗證用戶的密碼。在身份驗證過程中,PasswordEncoder會判定密碼是否有效。每個系統都會存儲以某種方式編碼過的密碼。最好把密碼哈希化存儲起來,這樣別人就不會讀到明文密碼了。PasswordEncoder還可以對密碼進行編碼。介面聲明的encode()和matches()方式實際上是對其職責的定義。這兩個方法都是同一介面的一部分,因此它們緊密相連。應用程式對密碼進行編碼的方式與驗證密碼的方式相關。
三、實現PasswordEncoder
3.1 使用預設的PasswordEncoder
在 Spring Security 5.0 之前,PasswordEncoder 預設值是 NoOpPasswordEncoder,這需要純文本密碼。 但現在您可能期望現在的預設值類似於BCryptPasswordEncoder。但是,這忽略了三個現實世界的問題:
- 許多應用程式使用無法輕鬆遷移的舊密碼編碼。
- 密碼存儲的最佳做法將再次更改。
- 作為一個框架,Spring 安全性不能經常進行重大更改。
相反,Spring Security 引入了 DelegatingPasswordEncoder,它通過以下方式解決了所有問題:
- 確保使用當前密碼存儲建議對密碼進行編碼
- 允許以現代和傳統格式驗證密碼
- 允許將來升級編碼
您可以使用PasswordEncoderFactories輕鬆構造DelegatingPasswordEncoder 的實例:
PasswordEncoder passwordEncoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
當然也可以選擇其它實例:
String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("sha256", new StandardPasswordEncoder());
PasswordEncoder passwordEncoder =
new DelegatingPasswordEncoder(idForEncode, encoders);
3.2 使用自定義的的PasswordEncoder
通常情況下,使用spring boot security自帶的password encoder已經足夠滿足使用場景了。筆者也不建議自己實現password encoder。
3.3 註入PasswordEncoder
在開發中,我們將 BCryptPasswordEncoder 的實例放入Spring容器即可
//密碼編碼器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}