Springboot2的Security框架用的是5.0的,較之4.0的密碼加密方式有了很大的改變.spring security 5中主推的加密方式為BCrypt,由於這種加密方式效率很低,屬於慢加密,但是加密強度很高,現有的機器性能難以暴力破解,但是隨着科技的進步,機器性能增強,破解這種加密方式也會成為可能,但是加密方式也會不斷更新.
廢話說到這里,由於性能要求,對該加密登錄的壓測,只能達到50-80qps,這無疑對高並發登錄是不能接受的,所以我們需要改掉這種加密方式,我們選擇了MD5的加密.修改之前的安全配置如下.
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public UserDetailsService userDetailsService; @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } /** * 全局用戶信息 * * @param auth * 認證管理 * @throws Exception * 用戶認證異常信息 */ @Autowired public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); } /** * 認證管理 * * @return 認證管理對象 * @throws Exception * 認證異常信息 */ @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * http安全配置 * * @param http * http安全對象 * @throws Exception * http安全異常信息 */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers(PermitAllUrl.permitAllUrl()).permitAll().anyRequest().authenticated().and() .httpBasic().and().csrf().disable(); } }
修改后,我們只使用MD5進行加密
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public UserDetailsService userDetailsService; // @Bean // public BCryptPasswordEncoder bCryptPasswordEncoder() { // return new BCryptPasswordEncoder(); // } @Bean PasswordEncoder passwordEncoder(){ String idForEncode = "MD5"; Map encoders = new HashMap<>(); encoders.put(idForEncode, new BCryptPasswordEncoder()); encoders.put("MD5", new MessageDigestPasswordEncoder("MD5")); PasswordEncoder delegatingPasswordEncoder = new DelegatingPasswordEncoder(idForEncode, encoders); return delegatingPasswordEncoder; // return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } /** * 全局用戶信息 * * @param auth * 認證管理 * @throws Exception * 用戶認證異常信息 */ @Autowired public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } /** * 認證管理 * * @return 認證管理對象 * @throws Exception * 認證異常信息 */ @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * http安全配置 * * @param http * http安全對象 * @throws Exception * http安全異常信息 */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers(PermitAllUrl.permitAllUrl()).permitAll().anyRequest().authenticated().and() .httpBasic().and().csrf().disable(); } }
這里需要注意的是,由於只使用了MD5進行加密,在訪問的時候,假設我們使用的是superadmin用戶名,密碼123456
http://192.168.5.182:36178/oauth/token?grant_type=password&client_id=system&client_secret=system&scope=app&username=superadmin&password=123456
這個client_id=system&client_secret=system在數據庫中是有對應的,之前的對應是用BCrypt加密的,所以在oauth_client_details表中,是這樣的
這里面的client_secret的值其實是system字符串的BCrypt加密結果,我們需要改成如下所示
這個值同樣也是system,不過是由MD5加密的結果,主要需要加前綴{MD5}.這樣在app_user表中,信息如下
密碼是由123456的MD5加密結果.這樣在訪問中,我們就可以獲取訪問的結果access_token
{"access_token":"65411be1-b7be-46e5-8d72-c0624da33ed7","token_type":"bearer","refresh_token":"43eb498f-d431-4c96-a5b5-3bc007c9c189","expires_in":25690,"scope":"app"}
但值得注意的是,有時候這樣修改后未必能得到我們所需要的結果,那是因為在redis中的緩存問題,由於前一次在BCrypt的加密下已經有了緩存,所以會報錯,我們需要手工清除一下Redis中的緩存,這樣就會重新建立MD5加密后的緩存,就不會再出現問題了.經過壓測,結果已經達到了2000左右的qps,已經大大高於50-80了.