javascript
使用Spring Boot 2使用OAuth2和不透明令牌进行集中授权
如果您正在尋找JWT實(shí)施,請點(diǎn)擊此鏈接
本指南逐步介紹了使用Spring Boot 2創(chuàng)建集中式身份驗(yàn)證和授權(quán)服務(wù)器的過程,還將提供演示資源服務(wù)器。
如果您不熟悉OAuth2,建議您閱讀此書。
先決條件
- JDK 1.8
- 文本編輯器或您喜歡的IDE
- Maven 3.0+
實(shí)施概述
對于這個(gè)項(xiàng)目,我們將通過Spring Boot使用Spring Security 5 。 如果您熟悉早期版本,那么《 Spring Boot遷移指南》可能會有用。
OAuth2術(shù)語
- 資源所有者
- 授權(quán)應(yīng)用程序訪問其帳戶的用戶。
- 資源服務(wù)器 :
- 在client獲取access token之后處理已認(rèn)證請求的服務(wù)器。
- 客戶
- 代表資源所有者訪問受保護(hù)資源的應(yīng)用程序。
- 授權(quán)服務(wù)器
- 在成功驗(yàn)證client和resource owner并授權(quán)請求之后,發(fā)出訪問令牌的服務(wù)器。
- 訪問令牌
- 用于訪問受保護(hù)資源的唯一令牌
- 范圍
- 許可
- 贈款類型
- grant是一種獲取訪問令牌的方法。
授權(quán)服務(wù)器
為了構(gòu)建我們的Authorization Server我們將通過Spring Boot 2.0.x使用Spring Security5.x 。
依存關(guān)系
您可以轉(zhuǎn)到start.spring.io并生成一個(gè)新項(xiàng)目,然后添加以下依賴項(xiàng):
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.1.2.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency> </dependencies>數(shù)據(jù)庫
出于本指南的考慮,我們將使用H2數(shù)據(jù)庫 。
在這里,您可以找到Spring Security所需的參考OAuth2 SQL模式。
然后添加以下條目
-- The encrypted client_secret it `secret` INSERT INTO oauth_client_details (client_id, client_secret, scope, authorized_grant_types, authorities, access_token_validity)VALUES ('clientId', '{bcrypt}$2a$10$vCXMWCn7fDZWOcLnIEhmK.74dvK1Eh8ae2WrWlhr2ETPLoxQctN4.', 'read,write', 'password,refresh_token,client_credentials', 'ROLE_CLIENT', 300); 上面的client_secret是使用bcrypt生成的。
前綴{bcrypt}是必需的,因?yàn)槲覀儗⑹褂肧pring Security 5.x的DelegatingPasswordEncoder的新功能。
在下面的頁面中,您可以找到Spring的org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl使用的User和Authority參考SQL模式。
CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(256) NOT NULL,password VARCHAR(256) NOT NULL,enabled TINYINT(1),UNIQUE KEY unique_username(username) );CREATE TABLE IF NOT EXISTS authorities (username VARCHAR(256) NOT NULL,authority VARCHAR(256) NOT NULL,PRIMARY KEY(username, authority) );與之前相同,為用戶及其權(quán)限添加以下條目。
-- The encrypted password is `pass` INSERT INTO users (id, username, password, enabled) VALUES (1, 'user', '{bcrypt}$2a$10$cyf5NfobcruKQ8XGjUJkEegr9ZWFqaea6vjpXWEaSqTa2xL9wjgQC', 1); INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER');Spring安全配置
添加以下Spring配置類。
import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl; import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder;import javax.sql.DataSource;@EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {private final DataSource dataSource;private PasswordEncoder passwordEncoder;private UserDetailsService userDetailsService;public WebSecurityConfiguration(final DataSource dataSource) {this.dataSource = dataSource;}@Overrideprotected void configure(final AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {if (passwordEncoder == null) {passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();}return passwordEncoder;}@Beanpublic UserDetailsService userDetailsService() {if (userDetailsService == null) {userDetailsService = new JdbcDaoImpl();((JdbcDaoImpl) userDetailsService).setDataSource(dataSource);}return userDetailsService;}}引用Spring Blog :
@EnableWebSecurity批注和WebSecurityConfigurerAdapter一起提供基于Web的安全性。
如果您使用的是Spring Boot,則將自動配置DataSource對象,您可以將其注入到類中,而不必自己定義。 需要將其注入到UserDetailsService中,該服務(wù)將使用Spring Security提供的JdbcDaoImpl ,如有必要,您可以將其替換為自己的實(shí)現(xiàn)。
由于某些自動配置的Spring @Bean需要Spring Security的AuthenticationManager因此有必要重寫authenticationManagerBean方法,并以@Bean authenticationManagerBean注釋。
PasswordEncoder將由PasswordEncoderFactories.createDelegatingPasswordEncoder()處理,其中基于前綴處理一些密碼編碼器和委托,在我們的示例中,我們使用{bcrypt}作為密碼的前綴。
授權(quán)服務(wù)器配置
授權(quán)服務(wù)器驗(yàn)證client和user憑證并提供令牌。
添加以下Spring配置類。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;import javax.sql.DataSource;@Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {private final DataSource dataSource;private final PasswordEncoder passwordEncoder;private final AuthenticationManager authenticationManager;private TokenStore tokenStore;public AuthorizationServerConfiguration(final DataSource dataSource, final PasswordEncoder passwordEncoder,final AuthenticationManager authenticationManager) {this.dataSource = dataSource;this.passwordEncoder = passwordEncoder;this.authenticationManager = authenticationManager;}@Beanpublic TokenStore tokenStore() {if (tokenStore == null) {tokenStore = new JdbcTokenStore(dataSource);}return tokenStore;}@Beanpublic DefaultTokenServices tokenServices(final ClientDetailsService clientDetailsService) {DefaultTokenServices tokenServices = new DefaultTokenServices();tokenServices.setSupportRefreshToken(true);tokenServices.setTokenStore(tokenStore());tokenServices.setClientDetailsService(clientDetailsService);tokenServices.setAuthenticationManager(authenticationManager);return tokenServices;}@Overridepublic void configure(final ClientDetailsServiceConfigurer clients) throws Exception {clients.jdbc(dataSource);}@Overridepublic void configure(final AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore());}@Overridepublic void configure(final AuthorizationServerSecurityConfigurer oauthServer) {oauthServer.passwordEncoder(passwordEncoder).tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}}用戶信息端點(diǎn)
現(xiàn)在,我們需要定義一個(gè)端點(diǎn),在該端點(diǎn)上可以將授權(quán)令牌解碼為Authorization對象,以添加以下類。
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController @RequestMapping("/profile") public class UserController {@GetMapping("/me")public ResponseEntityget(final Principal principal) {return ResponseEntity.ok(principal);}}資源服務(wù)器配置
資源服務(wù)器托管HTTP資源 ,其中的HTTP資源可以是文檔,照片或其他內(nèi)容,在我們的情況下,它將是受OAuth2保護(hù)的REST API。
依存關(guān)系
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.1.2.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency> </dependencies>定義我們受保護(hù)的API
下面的代碼定義了端點(diǎn)/me并返回Principal對象,它要求經(jīng)過身份驗(yàn)證的用戶具有ROLE_USER的訪問權(quán)限。
import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController @RequestMapping("/me") public class UserController {@GetMapping@PreAuthorize("hasRole('ROLE_USER')")public ResponseEntity<Principal> get(final Principal principal) {return ResponseEntity.ok(principal);}}@PreAuthorize批注會在執(zhí)行代碼之前驗(yàn)證用戶是否具有給定角色,以使其正常工作,有必要啟用prePost批注,為此添加以下類:
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;@EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfiguration {}這里的重要部分是@EnableGlobalMethodSecurity(prePostEnabled = true)批注, prePostEnabled標(biāo)志默認(rèn)情況下設(shè)置為false ,將其設(shè)置為true可使@PreAuthorize批注起作用。
資源服務(wù)器配置
現(xiàn)在,讓我們?yōu)橘Y源服務(wù)器添加Spring的配置。
import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;@Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {}來自Javadoc的@EnableResourceServer批注:
OAuth2資源服務(wù)器的便捷注釋,可啟用Spring Security過濾器,該過濾器通過傳入的OAuth2令牌對請求進(jìn)行身份驗(yàn)證。 用戶應(yīng)添加此批注并提供類型為{@link ResourceServerConfigurer}的@Bean (例如,通過{@link ResourceServerConfigurerAdapter}),用于指定資源的詳細(xì)信息(URL路徑和資源ID)。 為了使用此過濾器,您必須在應(yīng)用程序中的某個(gè)位置{@link EnableWebSecurity},使用該注釋的位置相同,也可以使用其他位置。
現(xiàn)在我們已經(jīng)準(zhǔn)備好所有必需的代碼,我們需要配置RemoteTokenServices ,對我們來說幸運(yùn)的是,Spring提供了一個(gè)配置屬性,可以在其中設(shè)置可以將令牌轉(zhuǎn)換為Authentication對象的url。
security:oauth2:resource:user-info-uri: http://localhost:9001/profile/me一起測試
為了一起測試,我們需要同時(shí)旋轉(zhuǎn)Authorization Server和Resource Server ,在我的設(shè)置中,它將相應(yīng)地在端口9001和9101上運(yùn)行。
生成令牌
$ curl -u clientId:secret -X POST localhost:9001/oauth/token\?grant_type=password\&username=user\&password=pass{"access_token" : "e47876b0-9962-41f1-ace3-e3381250ccea","token_type" : "bearer","refresh_token" : "8e17a71c-cb39-4904-8205-4d9f8c71aeef","expires_in" : 299,"scope" : "read write" }訪問資源
既然已經(jīng)生成了令牌,請復(fù)制access_token并將其添加到Authorization HTTP Header上的請求中,例如:
$ curl -i localhost:9101/me -H "Authorization: Bearer c06a4137-fa07-4d9a-97f9-85d1ba820d3a"{"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"remoteAddress" : "127.0.0.1","sessionId" : null,"tokenValue" : "c06a4137-fa07-4d9a-97f9-85d1ba820d3a","tokenType" : "Bearer","decodedDetails" : null},"authenticated" : true,"userAuthentication" : {"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"remoteAddress" : "127.0.0.1","sessionId" : null,"tokenValue" : "c06a4137-fa07-4d9a-97f9-85d1ba820d3a","tokenType" : "Bearer","decodedDetails" : null},"authenticated" : true,"userAuthentication" : {"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"grant_type" : "password","username" : "user"},"authenticated" : true,"principal" : {"password" : null,"username" : "user","authorities" : [ {"authority" : "ROLE_USER"} ],"accountNonExpired" : true,"accountNonLocked" : true,"credentialsNonExpired" : true,"enabled" : true},"credentials" : null,"name" : "user"},"clientOnly" : false,"oauth2Request" : {"clientId" : "clientId","scope" : [ "read", "write" ],"requestParameters" : {"grant_type" : "password","username" : "user"},"resourceIds" : [ ],"authorities" : [ {"authority" : "ROLE_CLIENT"} ],"approved" : true,"refresh" : false,"redirectUri" : null,"responseTypes" : [ ],"extensions" : { },"grantType" : "password","refreshTokenRequest" : null},"credentials" : "","principal" : {"password" : null,"username" : "user","authorities" : [ {"authority" : "ROLE_USER"} ],"accountNonExpired" : true,"accountNonLocked" : true,"credentialsNonExpired" : true,"enabled" : true},"name" : "user"},"authenticated" : true,"principal" : "user","credentials" : "N/A","name" : "user"},"principal" : "user","credentials" : "","clientOnly" : false,"oauth2Request" : {"clientId" : null,"scope" : [ ],"requestParameters" : { },"resourceIds" : [ ],"authorities" : [ ],"approved" : true,"refresh" : false,"redirectUri" : null,"responseTypes" : [ ],"extensions" : { },"grantType" : null,"refreshTokenRequest" : null},"name" : "user" }腳注
- 可以在GitHub上找到本指南使用的代碼
- OAuth 2.0
- Spring Security Java配置預(yù)覽
- Spring Boot 2 –遷移指南
- Spring– OAuth2開發(fā)人員指南
翻譯自: https://www.javacodegeeks.com/2019/03/centralized-authorization-with-oauth2-opaque-tokens-using-spring-boot-2.html
總結(jié)
以上是生活随笔為你收集整理的使用Spring Boot 2使用OAuth2和不透明令牌进行集中授权的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 光信号闪红灯是欠费吗移动
- 下一篇: 手机处理器天梯图(手机处理器天梯图202