Spring Security 基礎教程 -- 密碼加密和方法安全


密碼加密

一般來說,密碼是需要加密再存入數據庫的,常用哈希函數進行加密。

密碼加密與通信加密是有區別的。

通信加密是可逆加密,加密之后還需要解密,主要有對稱加密和非對稱加密兩種。密碼加密可以是單向加密,即加密之后不需要解密。

為了保證相同的明文加密后生成的密文不一樣,在加密過程中需要使用鹽(salt)。

在 Spring Security 中,提供了BCryptPasswordEncoder類,進行密碼的加密,且相同的明文,加密后的密文是不一樣的。

示例

在測試類中,寫一個測試方法:

@SpringBootTest
class SecurityApplicationTests {

    @Test
    void contextLoads() {
        for (int i=0; i<10; i++){
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            System.out.println(encoder.encode("123456"));
        }
    }
}

打印結果如下:

$2a$10$/zpce9GF4fW0xmfCWZk2MuHSX9frcj1JIMk7n1TPcUHDfU1clqy/i
$2a$10$Ihh9bkrN4KQjRF4BNbCwdeUgu779riYXofpVZu9djIjix2wAJo8tC
$2a$10$BnMc9GSCLKNrgXpKRgHNYucQqcm/Mu.W21pfmm/DEKvQ0qoeAqYs6
$2a$10$t2HljppbnA7NbBllkqgNB.lE655sD2ZPW6F2Y9ITZiEMJJTZUxTpS
$2a$10$WyZkBbv1VakuTJFm9AbEHOgtIt1ZjIPEIDpOLNdOnEjvcW.t34Vki
$2a$10$Lq3/QQLIgqiicGfEZL1YP.OVZ46X2WfPMOAz6iMJnNm/oWUs4/F1.
$2a$10$2e1PSKN80/WSWsxdUcrSHe2EmD30M4IZfQog6mGw9H5Ul1jfu63aK
$2a$10$VZcLRImtB18O1aV29ShRrONzygpCigBO3eROSyJ2035.AVkrgKpPa
$2a$10$SW9ydYyb9BCnmSPSmdg2P.NP4XBduCDIlnl.hxIh3/M/d/fUr83DK
$2a$10$hLWCemE7MVWtczl57shsQeF9nUILLmG0tooKh61sKW3Un17o18JSC

可以看出,相同的明文 123456 ,生成的 10 次密文都是不一樣的。

在方法configure(AuthenticationManagerBuilder auth),將明文密碼替換成密文密碼:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 調用加密算法 BCryptPasswordEncoder
     */
    @Bean
    PasswordEncoder passwordEncoder(){
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }

    /**
     * 定義兩個用戶,並設置密碼和角色
     * 從 Spring5.0 開始,密碼必須要加密
     * 基於內存的用戶認證
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password("$2a$10$9UwAaMnKSZHUloUl65mpWu01VF5ANLrmD/rsb6eGP4bc2f45.1.iG")
                .roles("admin")
                .and()
                .withUser("user1")
                .password("$2a$10$JnwOr9kXPg97mgOkUG2Qhe7b0Qrtr9BDm7G410p8sr6SPJoZupxP2")
                .roles("user");
    }
}

關於 BCryptPasswordEncoder的加密、驗證策略的源碼分析,參考文章:BCryptPasswordEncoder加密、驗證策略

方法安全

方法安全,即是直接在方法上加注解,來確保方法安全地執行。

示例

方法安全默認是關閉的,使用方法安全,首先需要在 SecurityConfig配置類上,加注解:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

新建一個 MethodService 類,在方法上進行安全注解:

@Service
public class MethodService {
    /**
     * 必須是角色 admin 才能調用這個方法
     */
    @PreAuthorize("hasRole('admin')")
    public String admin(){
        return "hello admin!";
    }

    /**
     * 只有角色 user 才能調用這個方法
     * @return
     */
    @Secured("ROLE_user")
    public String user(){
        return "hello user!";
    }

    /**
     * 角色 admin和user 都可以調用這個方法
     * @return
     */
    @PreAuthorize("hasAnyRole('admin', 'user')")
    public String hello(){
        return "hello hello!";
    }
}

再注入到 Controller 類中,測試一下 MethodService 中的方法:

    @Autowired
    MethodService methodService;

    @GetMapping("/hello1")
    public String hello1(){
        return methodService.admin();
    }

    @GetMapping("/hello2")
    public String hello2(){
        return methodService.user();
    }

    @GetMapping("/hello3")
    public String hello3(){
        return methodService.hello();
    }

如果使用角色 admin 登錄,就能成功調用接口 /hello1/hello3

如果使用角色 user 登錄,就能成功調用接口 /hello2/hello3

這就是方法安全。

每天學習一點點,每天進步一點點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM