?Spring Boot整合
1、RBAC
?權限模型
RBAC模型(Role-Based Access Control:基于角色的訪問控制)
在RBAC模型里面,有3個基礎組成部分,分別是:用戶、角色和權限,它們之間的關系如下圖所示
SELECT * FROM sec_permission;
SELECT * FROM sec_role_permission ;
SELECT * FROM sec_role;
SELECT * FROM sec_user_role;
SELECT * FROM sec_user;
2、啟動器依賴引入
啥配置也沒做,啥類也沒寫。只是增加了一個啟動器依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
重新訪問首頁:http://localhost:8080/
3、用戶名密碼
默認:
用戶名默認:user
密碼在服務啟動時打印在了控制臺
自定義:
?當然我們也可以通過application.yml指定配置用戶名密碼
security.user.name 指定默認的用戶名,默認為user.
security.user.password 默認的用戶密碼.
spring:security:user:name: adminpassword: admin
關閉security驗證:
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().permitAll().and().logout().permitAll();//配置不需要登錄驗證} }
WebSecurityConfigurerAdapter?是由Spring Security提供的Web應用安全配置的適配器
WebSecurityConfigurerAdapter
?是一個適配器類,允許開發者通過重寫特定的方法來自定義其 Web 安全配置
創建一個配置類WebSecurityConfig
繼承WebSecurityConfigurerAdapter
這個抽象類并重寫configure(HttpSecurity http)
方法,可以精確地定義哪些URL可以由哪些角色訪問。
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() // 表單方式.and().authorizeRequests() // 授權配置.anyRequest().authenticated(); //所有未匹配的請求都需要用戶進行身份驗證}
}
Spring Security提供了這種鏈式的方法調用。上面配置指定了認證方式為表單登錄,并且所有請求都需要進行認證。
HttpSecurity
?是 Spring Security 中用于構建安全配置的一個類。通過該類,開發者可以配置許多與 HTTP 安全相關的選項,如認證、授權、CORS、CSRF 保護等
.formLogin()
?是?HttpSecurity
?類的一個方法,用于啟用基于表單的身份驗證。當你調用這個方法時,Spring Security 會自動配置登錄表單的相關設置,如登錄頁面的 URL、登錄成功和失敗的處理等。你可以進一步定制這些設置,以適應你的應用程序需求。-------------------------------
http.authorizeRequests()
?是?HttpSecurity
?類的一個方法,用于定義 URL 的訪問權限。通過該方法,你可以指定哪些 URL 需要特定的角色或權限才能訪問,哪些 URL 可以公開訪問等。--------------
.anyRequest().authenticated()
?表示所有未匹配的請求都需要用戶進行身份驗證。
4、基于數據庫的登錄認證
Spring Security支持通過實現UserDetailsService接口的方式來提供用戶認證授權信息。主要功能:根據用戶名查詢用戶信息
@Service
public class CustomUserDetailsService implements UserDetailsService {@Autowiredprivate UserDao userDao;@Autowiredprivate RoleDao roleDao;@Autowiredprivate PermissionDao permissionDao;@Resourceprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//通過用戶名從數據庫獲取用戶信息User user = userDao.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("未找到用戶信息 : " + username));//定義權限列表List<GrantedAuthority> authorities = new ArrayList<>();authorities.add(new SimpleGrantedAuthority("a"));authorities.add(new SimpleGrantedAuthority("b"));authorities.add(new SimpleGrantedAuthority("c"));//返回spring security的User對象//user.getPassword() 數據庫中的密碼已經是密文存儲return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);}
}
返回值類型是UserDetails
,我們可以直接使用Spring Security提供的UserDetails
接口實現類org.springframework.security.core.userdetails.User
5、授權GrantedAuthority
GrantedAuthority
則表示用戶驗證通過后被授予的權限。
SimpleGrantedAuthority
SimpleGrantedAuthority
是默認的授權實現,它只存儲權限(存儲授予Authentication
對象的權限的String
表示形式),是一種簡易的授權實現。
GrantedAuthority:直譯"授予權限"
Authentication:直譯"驗證"
給我的感覺就是權限就是一個字符串,難道什么樣的字符串都行嗎?為啥定義的這么模糊
那我們就姑且給他"a","b","c"。。看看它怎么說
AuthorityUtils:此類一般用于UserDetailsService的實現類中的loadUserByUsername方法
作用為給user賬戶添加一個或多個權限,用逗號分隔,底層調用的是createAuthorityList方法,唯一區別在于此方法把所有的權限包含進一個字符串參數中,只不過用逗號分隔。
@Service public class UserDetailsServiceImpl implements UserDetailsService{@AutowiredPasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//比較密碼String pass=passwordEncoder.encode("123");//加密return new User(username,pass,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));}}
createAuthorityList
將權限轉換為List,如
@Service public class UserDetailsServiceImpl implements UserDetailsService{@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {List<GrantedAuthority> list=AuthorityUtils.createAuthorityList("admin","normal");//一個權限一個參數return new User(username,pass,list);} }
1
6、配置類中配置
實際項目中我們不會把密碼明文存儲在數據庫中。只需要使用把BCryptPasswordEncoder對象注入Spring容器中,SpringSecurity就會使用該PasswordEncoder來進行密碼校驗
Spring Security實現的BCryptPasswordEncoder
已經足夠強大,它對相同的密碼進行加密后可以生成不同的結果
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate UserDetailsService userDetailsService;@Beanpublic PasswordEncoder passwordEncoder() {//使用默認的BCryptPasswordEncoder加密方案return new BCryptPasswordEncoder();}/*** 配置用戶詳細信息的服務和密碼編碼器** @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//數據庫讀取的用戶進行身份認證auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() // 表單方式.and().authorizeRequests() // 授權配置.anyRequest().authenticated(); //所有未匹配的請求都需要用戶進行身份驗證}
}
Spring Security中的BCryptPasswordEncoder方法采用SHA-256 +隨機鹽+密鑰對密碼進行加密。SHA系列是Hash算法,不是加密算法,使用加密算法意味著可以解密(這個與編碼/解碼一樣),但是采用Hash處理,其過程是不可逆的。
1)加密(encode):注冊用戶時,使用SHA-256+隨機鹽+密鑰把用戶輸入的密碼進行hash處理,得到密碼的hash值,然后將其存入數據庫中。
2)密碼匹配(matches):用戶登錄時,密碼匹配階段并沒有進行密碼解密(因為密碼經過Hash處理,是不可逆的),而是使用相同的算法把用戶輸入的密碼進行hash處理,得到密碼的hash值,然后將其與從數據庫中查詢到的密碼hash值進行比較。如果兩者相同,說明用戶輸入的密碼正確。
再次訪問接口:http://127.0.0.1:8089/hello
使用賬號密碼登錄 admin/123456
7、權限控制
Spring Security
支持方法級別的權限控制。在此機制上,我們可以在任意層的任意方法上加入權限注解,加入注解的方法將自動被Spring Security
保護起來,僅僅允許特定的用戶訪問,從而還到權限控制的目的
@PreAuthorize() 該注解用于方法前驗證權限
//使用權限注解標明只有擁有“admin”權限的人才能訪問:???????@PreAuthorize("hasAuthority('admin')")
@RestController public class HelloController {@RequestMapping("/hello")public String sayHello() {return "hello";}@RequestMapping("/a")@PreAuthorize("hasAuthority('a')")public String sayA() {return "aaaaa";}@RequestMapping("/d")@PreAuthorize("hasAuthority('d')")public String sayB() {return "ddddd";} }
Spring Security
默認是禁用注解的,要想開啟注解,要在繼承WebSecurityConfigurerAdapter
的類加@EnableGlobalMethodSecurity()注解,并在該類中將AuthenticationManager
定義為Bean。說實話我沒有注入AuthenticationManager這個bean的時候,也做到了權限校驗。。這到底有啥用?
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate UserDetailsService userDetailsService;@Beanpublic PasswordEncoder passwordEncoder() {//使用默認的BCryptPasswordEncoder加密方案return new BCryptPasswordEncoder();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** 配置用戶詳細信息的服務和密碼編碼器** @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//數據庫讀取的用戶進行身份認證auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() // 表單方式.and().authorizeRequests() // 授權配置.anyRequest().authenticated(); //所有未匹配的請求都需要用戶進行身份驗證}
}
我們看到
@EnableGlobalMethodSecurity
?分別有prePostEnabled 、securedEnabled、jsr250Enabled
三個字段,其中每個字段代碼一種注解支持,默認為false,true為開啟
。
重新登錄訪問。記得之前我隨便給的權限字符串a,b,c。。。訪問a是沒問題的
訪問d會返回403錯誤碼。
自定義權限不足處理器來處理權限不足時候的操作
8、Session管理
用戶登錄成功后,信息保存在服務器Session中。如Tomcat
登錄后,可以看到cookie中存儲了JSESSIONID的cookie。
Session超時設置
如可以設置session有效期為1小時
server:session:timeout: 3600
這時候,就涉及到一個session共享
當應用集群部署的時候,用戶在A應用上登錄認證了,后續通過負載均衡可能會把請求發送到B應用,而B應用服務器上并沒有與該請求匹配的認證Session信息,所以用戶就需要重新進行認證
Spring Security默認的退出登錄URL為/logout
Spring Security OAuth2
1、什么是OAuth
OAuth是一種用來規范令牌(Token)發放的授權機制,主要包含了四種授權模式:授權碼模式、簡化模式、密碼模式和客戶端模式
OAuth相關的名詞
-
Third-party application?第三方應用程序,比如這里的虎牙直播;
-
HTTP service?HTTP服務提供商,比如這里的QQ(騰訊);
-
Resource Owner?資源所有者,就是QQ的所有人,你;
-
User Agent?用戶代理,這里指瀏覽器;
-
Authorization server?認證服務器,這里指QQ提供的第三方登錄服務;
-
Resource server?資源服務器,這里指虎牙直播提供的服務,比如高清直播,彈幕發送等(需要認證后才能使用)。
Spring Security OAuth2主要包含認證服務器和資源服務器這兩大塊的實現:
認證服務器主要包含了四種授權模式的實現和Token的生成與存儲
資源服務器主要是在Spring Security的過濾器鏈上加了OAuth2AuthenticationProcessingFilter過濾器,即使用OAuth2協議發放令牌認證的方式來保護我們的資源
2、認證授權服務器
創建認證服務器很簡單,只需要在Spring Security的配置類上使用@EnableAuthorizationServer
注解標注即可
使用?
@EnableAuthorizationServer
?注解,在應用中自動開啟和配置 Spring Security OAuth 的授權服務組件。?
@EnableAuthorizationServer
?注解主要是導入兩個配置類,分別是:
AuthorizationServerEndpointsConfiguration
,這個配置類主要配置授權端點,獲取token的端點。大家就把對應的端點想象成controller即可,在這個controller下開放了若干個@RequestMapping,比如常見的有:/oauth/authorize(授權路徑)
,/oauth/token(獲取token)
等AuthorizationServerSecurityConfiguration
,主要是做spring-security的安全配置
3、資源服務器
資源服務器的配置也很簡單,只需要在配置類上使用@EnableResourceServer
注解標注即可:
通過資源服務器來保護我們指定的資源,必須在獲取授權認證的時候才能訪問。在SpringBoot當中,我們可以通過@EnableResourceServer
注解來開啟此功能。
@Configuration@EnableResourceServerpublic class ResourceConfigure extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests().antMatchers("/free/**").permitAll().and().authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll();//必須認證過后才可以訪問}}