您好,登錄后才能下訂單哦!
本篇內容主要講解“如何理解SpringSecurity原理認證”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何理解SpringSecurity原理認證”吧!
項目結構基本沒有變:
首先我們需要實現UserDetailsService,來獲取用戶相關的信息封裝類UserDetails。
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; @Service public class MyUserDetailService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("admin"); // 這里可以訪問數據庫、緩存等獲取用戶信息,然后構建為User,User是UserDetails的實現類 return User.builder() .username("bob")//用戶名 //密碼 111111 通過BCryptPasswordEncoder加密之后的密文 .password("$2a$10$344aKAgXr17q7u.8l5i7Cu8wUJr/cxBIniLsVtf/WwFrPx0khY62K") .authorities("admin")//權限信息 .build(); } }
UserDetailsService只做一件事情,就是獲取UserDetails,主要是用戶名、密碼和權限。可以使用Spring Security為我們提供的實現類User,也可以自己實現UserDetails,按自己需求封裝。
有了怎樣獲取UserDetails的方法,我們當然還要通過SecurityConfig配置的AuthenticationManagerBuilder告訴Spring Security。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import vip.oschool.uinion.security.MyUserDetailService; import javax.annotation.Resource; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource MyUserDetailService myUserDetailService; @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailService); } }
注意,我們同時還添加了一個BCryptPasswordEncoder,這是一個密碼加密器,因為一般情況數據庫存放的都是密碼的密文,所以,我們還要告訴Spring Security,我們數據庫的密碼的加密方式是什么,這樣Spring Security才能把從客戶端接收到的密碼使用同樣的方式加密,然后做認證。
當然,你也可以通過下面的方式來設置密碼加密器:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailService).passwordEncoder(new BCryptPasswordEncoder()); }
下面我們把配置文件中的用戶名和密碼注釋掉,重新啟動,然后就可以通過我們在UserDetailsService實現中設置的用戶bob和密碼111111來完成認證。
server: port: 8081 #spring: # security: # user: # name: tim # password: 111111
一個比較抽象的概念,用于唯一標識實體的類。
例如,對于用戶來說:用戶id、手機號、郵箱就可以作為用戶的principal來標志用戶。
簡單點理解,就可以看做是密碼。
先知道是:角色與權限,具體的后面詳細介紹。
用戶實體的接口,通過這個接口可以獲取:
getPassword: 獲取密碼
getUserName: 獲取用戶名
isEnabled: 賬戶是否可用
isAccountNonExpired: 賬戶是否過期
isAccountNonLocked: 賬戶是否被鎖定
isCredentialsNonExpired: 密碼是否過期
getAuthorites:獲取用戶權限,本質上是用戶的角色信息
Spring Security中是:org.springframework.security.core.userdetails.UserDetails
Spring Security提供了一個默認的實現類:org.springframework.security.core.userdetails.User
這個接口只有一個目的,就是獲取UserDetails,例如,我們需要從數據庫獲取用戶,就需要實現這個接口,并把實現類注入到Spring容器中。
只需要獲取UserDetails,認證的工作Spring Security自己獲通過用戶名和密碼來驗證,中間可能還涉及一下密碼處理的過程。
用于存儲用戶認證詳細信息:principal、權限GrantedAuthority等。
自定義的Authentication可以實現Authentication接口,也可以直接繼承AbstractAuthenticationToken。
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import java.util.Collection; public class JwtAuthenticationToken extends AbstractAuthenticationToken { public JwtAuthenticationToken(Collection<? extends GrantedAuthority> authorities) { super(authorities); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return null; } }
AuthenticationProvider,顧名思義,認證的提供者,就是用于執行特定類型的身份認證的接口。
我們如果要自定義認證,就需要實現這個接口,例如,現在很多前后端分離項目使用JWT方式來鑒權,那每個請求怎樣校驗Token呢?
我們就可以創建一個JWTAuthenticationProvider實現AuthenticationProvider,來完成JWT token的認證工作。
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; public class JwtAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { return null; } @Override public boolean supports(Class<?> authentication) { return authentication.isAssignableFrom(JwtAuthenticationToken.class); } }
然后可以通過下面的方式把我們自定義的AuthenticationProvider注入。
@EnableWebSecurity() public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(daoAuthenticationProvider()) .authenticationProvider(jwtAuthenticationProvider()); } }
前面,我們使用的UserDetailService為什么能生效,是因為做了下面的配置:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailService); }
認證管理器構建者AuthenticationManagerBuilder的userDetailsService會創建一個DaoAuthenticationProvider,DaoAuthenticationProvider使用DelegatingPasswordEncoder的是一個代理,默認使用的是BCryptPasswordEncoder。
AuthenticationManager,顧名思義,是用來管理Authentication,其實是管理AuthenticationProvider。
ProviderManager是AuthenticationManager的實現類,它持有一個AuthenticationProvider列表,用來完成不同的認證。
它還持有一個AuthenticationManager的引用,作為其父類。
一般來說我們使用ProviderManager就夠了,一般也只需要一個AuthenticationProvider。
如果要配置多個,可以在SecurityConfig(繼承了WebSecurityConfigurerAdapter)重寫authenticationManager。
@Override protected AuthenticationManager authenticationManager() { // ProviderManager可以設置多個AuthenticationProvider ProviderManager authenticationManager = new ProviderManager(Arrays.asList()); return authenticationManager; }
簡單的說就是用于對密碼進行加密,存儲用戶密碼的明文絕對不是什么好的習慣,這是對用戶的不負責任,也是項目存在風險。
所以,我們一般都會對用戶的密碼進行加密之后再存儲,通常的做法是加鹽然后使用sha256再md5之類的算法。
使用Spring Security就需要我們自己實現這些過程了,直接配置PasswordEncoder就可以了。
Spring Security為PasswordEncoder提供了下面一些實現類。
即委托密碼編碼器,兼容多種不同加密方式存儲密碼。主要用于新舊數據的加密方式的兼容,做到平滑遷移,例如舊數據使用NoOpPasswordEncoder,新數據使用BCryptPasswordEncoder加密。
基于bcrypt算法的編碼器,為了使其更能抵御密碼破解,bcrypt故意降低了速度,與其他自適應單向功能一樣,應將其調整為大約1秒鐘,以驗證系統上的密碼。BCryptPasswordEncoder的默認實現使用強度10。
基于 Argon2算法的編碼器,Argon2是一種故意慢速的算法,需要大量內存。 與其他自適應單向功能一樣,應將其調整為大約1秒鐘,以驗證系統上的密碼。 Argon2PasswordEncoder的當前實現需要BouncyCastle。
基于 PBKDF2算法的編碼器,為了克服密碼破解問題,PBKDF2是一種故意緩慢的算法。 與其他自適應單向功能一樣,應將其調整為大約1秒鐘,以驗證系統上的密碼。 當需要FIPS認證時,此算法是一個不錯的選擇。
基于scrypt算法的編碼器, 為了克服自定義硬件scrypt上的密碼破解問題,這是一種故意緩慢的算法,需要大量內存。 與其他自適應單向功能一樣,應將其調整為大約1秒鐘,以驗證系統上的密碼。
我們測試的時候,想要添加測試用戶,但是又不想太麻煩的去實現UserDetailsService,也可以通過下面的方式:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("tim") .password("111111").roles("admin") .and() .withUser("allen") .password("222222") .roles("user"); } }
進入inMemoryAuthentication方法,我們可以看到上面的方式等價于:
@Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("tim").password("111111").roles("admin").build()); manager.createUser(User.withUsername("allen").password("222222").roles("user").build()); return manager; }
所以,本質上還是相當于創建了一個UserDetailsService,只不過數據保存在內存中。
到此,相信大家對“如何理解SpringSecurity原理認證”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。