您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“SpringBoot安全管理之OAuth2框架怎么使用”,內容詳細,步驟清晰,細節處理妥當,希望這篇“SpringBoot安全管理之OAuth2框架怎么使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
OAuth 是一個開放標準,該標準允許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密資源(如頭像、照片、視頻等),而在這個過程中無須將用戶名和密碼提供給第三方應用。
實現這一功能是通過一個令牌(token),而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每一個令牌授權一個特定的網站在特定的時間段內訪問特定的資源。
這樣 OAuth 讓用戶可以授權第三方網站靈活的訪問存儲在另一些資源服務器的特定信息,而非所有內容。例如,用戶想通過 QQ 登錄知乎,這時知乎就是一個第三方應用,知乎要訪問用戶的一些基本信息就需要得到用戶的授權,如果用戶把自己的 QQ 用戶名和密碼告訴知乎,那么知乎就能訪問用戶的所有數據,并且只有用戶修改密碼才能收回權限,這種授權方式安全隱患很大,如果使用 OAuth ,就能很好的解決這一問題。
采用令牌的方式可以讓用戶靈活的對第三方應用授權或者收回權限。OAuth 2 是 OAuth 協議的下一版本,但不向下兼容 OAuth 1.0 。
OAuth 2 關注客戶端開發者的簡易型,同時為Web應用、桌面應用,移動設備、起居室設備提供專門的認證流程。傳統的 Web 開發登錄認證一般都是基于 Session 的,但是前后端分離的架構中繼續使用 Session 會有許多不便,因為移動端(Android、IOS、微信小程序等)要么不支持 Cookie(微信小程序),要么使用非常不便,對于這些問題,使用 OAuth 2 認證都能解決。
先了解 OAuth 2 中幾個基本的角色
資源所有者:即用戶,具有頭像、照片、視頻等資源
客戶端:即第三方應用
授權服務器:用來驗證用戶提供的信息是否正確,并返回一個令牌給第三方應用
資源服務器:提供給用戶資源的服務器,例如頭像、照片、視頻等資源
一般來說,授權服務器和資源服務器可以是同一臺服務器。
步驟01:客戶端(第三方應用)向用戶請求授權。
步驟02:用戶單擊客戶端所呈現的服務授權頁面上的同意授權按鈕后,服務端返回一個授權許可憑證給客戶端。
步驟03:客戶端拿著授權許可證去授權服務器申請令牌。
步驟04:授權服務器驗證信息無誤后,發放令牌給客戶端。
步驟05:客戶端拿著令牌去資源服務器訪問資源。
步驟06:資源服務器驗證令牌無誤后開放資源。
OAuth 協議的授權模式共分為 4 種,如下
授權碼模式:授權碼(authorization code)是功能最完整、流程最嚴謹的授權模式。它的特點就是通過客戶端的服務器與授權服務器進行交互,國內常見的第三方平臺登錄功能基本都是使用這種模式
簡化模式:簡化模式不需要客戶端服務器參與,直接在瀏覽器中向授權服務器申請令牌,一般若是純靜態頁面,則可以采用這種方式
密碼模式:用戶把用戶名密碼直接告訴客戶端,客戶端使用這些信息向授權服務器申請令牌。這需要用戶對客戶端高度信息,例如客戶端應用和服務提供商是同一家公司
客戶端模式:客戶端使用自己的名義而不是用戶的名義想服務提供者申請授權。嚴格來說,客戶端模式并不能算作 OAuth 協議要解決的問題的一種解決方案,但是,對于開發者而言,在一些前后端分離應用或者為移動端提供的認證授權服務器上使用這種模式還是非常方便的
4 種模式各有千秋,分別適用于不同的開發場景,開發者根據實際情況進行選擇
此處介紹的是在前后端分離應用(或為移動端、微信小程序等)提供的認證服務器中如何搭建 OAuth 服務,因此主要介紹密碼模式。
創建 Spring Boot Web 項目,添加如下依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth3</artifactId> <version>2.3.3.RELEASE</version> </dependency>
由于 Spring Boot 中的 OAuth 協議是在 Spring Security 的基礎上完成的,因此首先要添加 Spring Security 依賴,要用到 OAuth 2,因此添加 OAuth 2 相關依賴,令牌可以存儲在 Redis 緩存服務器上,同時 Redis 具有過期等功能,很適合令牌的存儲,因此也加入 Redis 依賴。
配置 application.properties
spring.redis.database=0
spring.redis.host=ip地址
spring.redis.port=6379
spring.redis.password=root
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
授權服務器和資源服務器可以是同一臺服務器,也可以是不同服務器,此處假設是同一臺服務器,通過不同的配置分別開啟授權服務器和資源服務器,首先是授權服務器:
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired AuthenticationManager authenticationManager; @Autowired RedisConnectionFactory redisConnectionFactory; @Autowired UserDetailsService userDetailsService; @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("password") .authorizedGrantTypes("password", "refresh_token") .accessTokenValiditySeconds(1800) .resourceIds("rid") .scopes("all") .secret("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory)) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.allowFormAuthenticationForClients(); } }
代碼解釋:
自定義類繼承自 AuthorizationServerConfigurerAdapter ,完成對授權服務器的配置,然后通過 @EnableAuthorizationServer 注解開啟授權服務器
注入 AuthenticationManager 用來支持 password 模式
注入 RedisConnectionFactory 用來完成 Redis 緩存,將令牌信息儲存到 Redis 緩存中
注入 UserDetailsService 該對象為刷新 token 提供支持
在 configure(ClientDetailsServiceConfigurer clients) 方法中配置 password 授權模式,authorizedGrantTypes 表示 OAuth 2 中的授權模式為 password 和 refresh_token 兩種,在標準的 OAuth 2 協議中,授權模式并不包括 refresh_token ,但是在 Spring Security 的實現中將其歸為一種,因此如果要實現 access_token 的刷新,就需要添加這樣一種授權模式;accessTokenValiditySeconds 方法配置了 access_token 的過期時間;resourceIds 配置了資源 id;secret 方法配置了加密后的密碼,明文是 123
configure(AuthorizationServerEndpointsConfigurer endpoints) 方法配置了令牌的存儲,AuthenticationManager 和 UserDetailsService 主要用于支持 password 模式以及令牌的刷新
configure(AuthorizationServerSecurityConfigurer security) 方法配置表示支持 client_id 和 client_secret 做登錄認證
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId("rid").stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin") .antMatchers("/user/**").hasRole("user") .anyRequest().authenticated(); } }
代碼解釋:
自定義類繼承自 ResourceServerConfigurerAdapter ,并添加 @EnableResourceServer 注解開啟資源服務器配置
resources.resourceId(“rid”).stateless(true); 配置資源 id,這里的資源 id 和授權服務器中的資源 id 一直,然后設置這些資源僅基于令牌認證
configure(HttpSecurity http) 方法配置 HttpSecurity
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean @Override protected UserDetailsService userDetailsService() { return super.userDetailsService(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin") .password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq") .roles("admin") .and() .withUser("sang") .password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq") .roles("user"); } @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/oauth/**").authorizeRequests() .antMatchers("/oauth/**").permitAll() .and().csrf().disable(); } }
這里兩個 Bean 將注入授權服務器配置類中使用,另外,這里的 HttpSecurity 配置主要是配置 /oauth/** 模式的 URL ,這一類的請求直接放行。在 Spring Security 配置和資源服務器配置中,一共涉及兩個 HttpSecurity ,其中 Spring Security 中的配置優先級高于資源服務器中的配置,即請求地址先經過 Spring Security 的 HttpSecurity ,再經過資源服務器的 HttpSecurity。
首先創建三個簡單的請求地址
@RestController public class HelloController { @GetMapping("/admin/hello") public String admin() { return "Hello admin!"; } @GetMapping("/user/hello") public String user() { return "Hello user!"; } @GetMapping("/hello") public String hello() { return "hello"; } }
根據前文的配置,要請求這三個地址,分別需要 admin 角色、user 角色以及登錄后訪問。
所有都配置完成后,啟動 Redis 服務器,再啟動 Spring Boot 項目,首先發送一個 POST 請求獲取 token,請求地址如下(注意這里是一個 POST 請求,為了顯示方便,將參數寫在地址欄中):http://localhost:8080/oauth/token?username=sang&password=123&grant_type=password&client_id=password&scope=all&client_secret=123
請求地址中包含的參數有用戶名、密碼、授權模式、客戶端 id 、scope 以及客戶端密碼,基本就是授權服務器中所配置的數據,請求結果如圖
其中 access_token 是獲取其它資源時要用的令牌,refresh_token 用來刷新令牌,expires_in 表示 access_token 過期時間,當 access_token 過期后,使用 refresh_token 重新獲取新的 access_token (前提是 refresh_token 未過期),請求地址(注意也是POST請求):http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=693b0e36-4515-442a-8c5d-90bade3c74d2&client_id=password&client_secret=123
獲取新的 access_token 時需要攜帶上 refresh_token ,同事授權模式設置為 refresh_token ,在獲取的結果中 access_token 會變化,同時 access_token 有效期也會變化,如圖
接下來訪問所有資源,攜帶上 access_token 參數即可,例如 /user/hello 接口:http://localhost:8080/user/hello?access_token=0497e4bc-df37-460e-8755-b813b9dbf36a,訪問結果如圖
如果非法訪問一個資源,例如 sang 用戶訪問 /admin/hello 接口,結果如圖
到此,一個 password 模式的 OAuth 認證體系就搭建成功了。
OAuth 中的認證模式有 4 中,開發者需要結合自己開發的實際情況選擇其中一種,此處介紹的是在前后端分離應用中常用的 password 模式,其它的授權模式也都有自己的使用場景。
整體來講,Spring Security OAuth 2 的使用還是較復雜的,配置也比較繁瑣,如果開發者的應用場景比較簡單,完全可以按照此處介紹的授權流程自己搭建 OAuth 2 認證體系。
讀到這里,這篇“SpringBoot安全管理之OAuth2框架怎么使用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。