Spring Security(二)

yliu.best發表於2019-01-11

Spring Security(二)

注:凡是原始碼部分,我已經把英文註釋去掉了,有興趣的同學可以在自己專案裡進去看看。?

定義使用者認證邏輯

使用者登入成功後,使用者的資訊會被 Security 封裝在一個介面裡(“UserDetailsService”)

UserDetailsService 原始碼:

public interface UserDetailsService {
   // UserDetails 封裝的使用者資訊介面
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

處理密碼加密解密

Spring Security 處理登入密碼的是 PasswordEncoder 介面。

PasswordEncoder 原始碼:

public interface PasswordEncoder {
    
    // 用來把使用者登入時傳入的密碼進行加密處理
  String encode(CharSequence rawPassword);
    
    // 用來判斷加密後的密碼和使用者傳入的程式碼是否匹配
  boolean matches(CharSequence rawPassword, String encodedPassword);

}

Security 為 PasswordEncoder 介面提供了預設的實現 BCryptPasswordEncoder ,在專案中配置上密碼加解密如下:

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        // Security 預設實現
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 啟用表單登陸
        http.formLogin()
            .and()
            // 對請求做授權
            .authorizeRequests()
            // 任何請求
            .anyRequest()
            // 都需要身份認證
            .authenticated();
    }
}

配置 UserDetailService 介面實現:

@Configuration
public class MyUserDetailsService implements UserDetailsService {

    private static final Logger log = LoggerFactory.getLogger(MyUserDetailsService.class);

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("登入使用者名稱 ={}", username);
        // 根據使用者名稱查詢使用者資訊(此處省略與資料庫互動邏輯)
        // 下面的“User”物件是Security的,它實現了UserDetailsService介面
        List<GrantedAuthority> grantedAuthorities =
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        // 根據查詢到的使用者資訊判斷使用者是否被凍結
        String encode = passwordEncoder.encode("123456");
        log.info("加密後的密碼 ={}", encode);
        return new User(username, encode,
                true, true, true, true, grantedAuthorities);
    }

}

登入後,日誌如下:

2019-01-10 01:22:10.946  INFO 6572 --- [nio-8081-exec-3] c.i.s.browser.MyUserDetailsService       : 登入使用者名稱 =root
2019-01-10 01:22:11.074  INFO 6572 --- [nio-8081-exec-3] c.i.s.browser.MyUserDetailsService       : 加密後的密碼 =$2a$10$8NCzA8f.T9vLijKnrI9BKOKVB53FB4esFG1QlaBT1Fmh2I5ITjRGm

由此可見,Security 預設的加解密介面實現中的密碼加密並不是我們所熟悉的 MD5 ,如果想使用 MD5 加密,可自定義一個 PasswordEncoder 介面的實現類,如下:

/**
 * 自定義 PasswordEncoder 介面實現
 */
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        String pwd = rawPassword.toString();
        return DigestUtil.md5Hex(pwd);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return this.encode(rawPassword).equalsIgnoreCase(encodedPassword);
    }
}
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        // Security 自定義實現
        return new MyPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 啟用表單登陸
        http.formLogin()
            .and()
            // 對請求做授權
            .authorizeRequests()
            // 任何請求
            .anyRequest()
            // 都需要身份認證
            .authenticated();
    }
}

相關文章