javascript
使用Spring Boot 2通过OAuth2和JWT进行集中授权
本指南逐步介紹了使用Spring Boot 2創(chuàng)建集中式身份驗證和授權服務器的過程,還將提供演示資源服務器。
如果您不熟悉OAuth2,建議您閱讀此書。
先決條件
- JDK 1.8
- 文本編輯器或您喜歡的IDE
- Maven 3.0+
實施概述
對于這個項目,我們將通過Spring Boot使用Spring Security 5 。 如果您熟悉早期版本,那么《 Spring Boot遷移指南》可能會有用。
OAuth2術語
- 資源所有者
- 授權應用程序訪問其帳戶的用戶。
- 資源服務器 :
- 在client獲取access token之后處理已認證請求的服務器。
- 客戶
- 代表資源所有者訪問受保護資源的應用程序。
- 授權服務器
- 在成功驗證client和resource owner并授權請求之后,發(fā)出訪問令牌的服務器。
- 訪問令牌
- 用于訪問受保護資源的唯一令牌
- 范圍
- 許可
- 智威湯遜
- JSON Web令牌是一種用于在RFC 7519中定義的在雙方之間安全地表示聲明的方法
- 贈款類型
- grant是一種獲取訪問令牌的方法。
授權服務器
為了構建我們的Authorization Server我們將通過Spring Boot 2.1.x使用Spring Security5.x 。
依存關系
您可以轉到start.spring.io并生成一個新項目,然后添加以下依賴項:
<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ù)據庫
在本教程中,我們將使用H2數(shù)據庫 。
在這里,您可以找到Spring Security所需的參考OAuth2 SQL模式。
注意:由于本教程使用JWT并非所有表都是必需的。
然后添加以下條目
-- 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}是必需的,因為我們將使用Spring 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) );與之前相同,為用戶及其權限添加以下條目。
-- 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中,該服務將使用Spring Security提供的JdbcDaoImpl ,如有必要,您可以將其替換為自己的實現(xiàn)。
由于某些自動配置的Spring @Bean需要Spring Security的AuthenticationManager因此有必要重寫authenticationManagerBean方法,并以@Bean authenticationManagerBean注釋。
PasswordEncoder將由PasswordEncoderFactories.createDelegatingPasswordEncoder()處理,其中基于前綴處理一些密碼編碼器和委托,在我們的示例中,我們使用{bcrypt}作為密碼的前綴。
授權服務器配置
授權服務器會驗證client和user憑據并提供令牌,在本教程中,我們將生成JSON Web Tokens aka JWT 。
為了對生成的JWT令牌進行簽名,我們將使用自簽名證書,并在使用Spring Configuration開始之前這樣做,讓我們創(chuàng)建一個@ConfigurationProperties類來綁定我們的配置屬性。
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.io.Resource;@ConfigurationProperties("security") public class SecurityProperties {private JwtProperties jwt;public JwtProperties getJwt() {return jwt;}public void setJwt(JwtProperties jwt) {this.jwt = jwt;}public static class JwtProperties {private Resource keyStore;private String keyStorePassword;private String keyPairAlias;private String keyPairPassword;public Resource getKeyStore() {return keyStore;}public void setKeyStore(Resource keyStore) {this.keyStore = keyStore;}public String getKeyStorePassword() {return keyStorePassword;}public void setKeyStorePassword(String keyStorePassword) {this.keyStorePassword = keyStorePassword;}public String getKeyPairAlias() {return keyPairAlias;}public void setKeyPairAlias(String keyPairAlias) {this.keyPairAlias = keyPairAlias;}public String getKeyPairPassword() {return keyPairPassword;}public void setKeyPairPassword(String keyPairPassword) {this.keyPairPassword = keyPairPassword;}} }添加以下Spring配置類。
import com.marcosbarbero.lab.sec.oauth.jwt.config.props.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; 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.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;import javax.sql.DataSource; import java.security.KeyPair;@Configuration @EnableAuthorizationServer @EnableConfigurationProperties(SecurityProperties.class) public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {private final DataSource dataSource;private final PasswordEncoder passwordEncoder;private final AuthenticationManager authenticationManager;private final SecurityProperties securityProperties;private JwtAccessTokenConverter jwtAccessTokenConverter;private TokenStore tokenStore;public AuthorizationServerConfiguration(final DataSource dataSource, final PasswordEncoder passwordEncoder,final AuthenticationManager authenticationManager, final SecurityProperties securityProperties) {this.dataSource = dataSource;this.passwordEncoder = passwordEncoder;this.authenticationManager = authenticationManager;this.securityProperties = securityProperties;}@Beanpublic TokenStore tokenStore() {if (tokenStore == null) {tokenStore = new JwtTokenStore(jwtAccessTokenConverter());}return tokenStore;}@Beanpublic DefaultTokenServices tokenServices(final TokenStore tokenStore,final ClientDetailsService clientDetailsService) {DefaultTokenServices tokenServices = new DefaultTokenServices();tokenServices.setSupportRefreshToken(true);tokenServices.setTokenStore(tokenStore);tokenServices.setClientDetailsService(clientDetailsService);tokenServices.setAuthenticationManager(this.authenticationManager);return tokenServices;}@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {if (jwtAccessTokenConverter != null) {return jwtAccessTokenConverter;}SecurityProperties.JwtProperties jwtProperties = securityProperties.getJwt();KeyPair keyPair = keyPair(jwtProperties, keyStoreKeyFactory(jwtProperties));jwtAccessTokenConverter = new JwtAccessTokenConverter();jwtAccessTokenConverter.setKeyPair(keyPair);return jwtAccessTokenConverter;}@Overridepublic void configure(final ClientDetailsServiceConfigurer clients) throws Exception {clients.jdbc(this.dataSource);}@Overridepublic void configure(final AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(this.authenticationManager).accessTokenConverter(jwtAccessTokenConverter()).tokenStore(tokenStore());}@Overridepublic void configure(final AuthorizationServerSecurityConfigurer oauthServer) {oauthServer.passwordEncoder(this.passwordEncoder).tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}private KeyPair keyPair(SecurityProperties.JwtProperties jwtProperties, KeyStoreKeyFactory keyStoreKeyFactory) {return keyStoreKeyFactory.getKeyPair(jwtProperties.getKeyPairAlias(), jwtProperties.getKeyPairPassword().toCharArray());}private KeyStoreKeyFactory keyStoreKeyFactory(SecurityProperties.JwtProperties jwtProperties) {return new KeyStoreKeyFactory(jwtProperties.getKeyStore(), jwtProperties.getKeyStorePassword().toCharArray());} }在上面的類中,您將找到JWT所需的所有Spring @Bean 。 最重要的@Bean是: JwtAccessTokenConverter , JwtTokenStore和DefaultTokenServices 。
JwtAccessTokenConverter使用自簽名證書對生成的令牌進行簽名。
JwtTokenStore實現(xiàn)僅從令牌本身讀取數(shù)據。 并不是真正的商店,因為它從不持久化任何東西,它使用JwtAccessTokenConverter生成和讀取令牌。
DefaultTokenServices使用TokenStore來保留令牌。
按照本指南生成自簽名證書 。
生成自簽名證書后,在application.yml上配置它。
security:jwt:key-store: classpath:keystore.jkskey-store-password: letmeinkey-pair-alias: mytestkeykey-pair-password: changeme資源服務器配置
資源服務器托管HTTP資源 ,其中的HTTP資源可以是文檔,照片或其他內容,在我們的情況下,它將是受OAuth2保護的REST API。
依存關系
<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><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency> </dependencies>定義我們受保護的API
下面的代碼定義了返回/me Principal的端點/me ,它要求經過身份驗證的用戶具有ROLE_USER的訪問權限。
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í)行代碼之前驗證用戶是否具有給定角色,以使其正常工作,有必要啟用prePost批注,為此添加以下類:
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;@EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfiguration {}這里的重要部分是@EnableGlobalMethodSecurity(prePostEnabled = true)批注, prePostEnabled標志默認情況下設置為false 。
資源服務器配置
解碼JWT令牌就必須使用public key從自簽名的認證上使用的授權服務器簽署的道理,做讓我們先創(chuàng)建一個@ConfigurationProperties類綁定配置屬性。
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.io.Resource;@ConfigurationProperties("security") public class SecurityProperties {private JwtProperties jwt;public JwtProperties getJwt() {return jwt;}public void setJwt(JwtProperties jwt) {this.jwt = jwt;}public static class JwtProperties {private Resource publicKey;public Resource getPublicKey() {return publicKey;}public void setPublicKey(Resource publicKey) {this.publicKey = publicKey;}}}使用以下命令從生成的JKS導出public key :
$ keytool -list -rfc --keystore keystore.jks | openssl x509 -inform pem -pubkey -noout樣本響應如下所示:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmWI2jtKwvf0W1hdMdajc h+mFx9FZe3CZnKNvT/d0+2O6V1Pgkz7L2FcQx2uoV7gHgk5mmb2MZUsy/rDKj0dM fLzyXqBcCRxD6avALwu8AAiGRxe2dl8HqIHyo7P4R1nUaea1WCZB/i7AxZNAQtcC cSvMvF2t33p3vYXY6SqMucMD4yHOTXexoWhzwRqjyyC8I8uCYJ+xIfQvaK9Q1RzK Rj99IRa1qyNgdeHjkwW9v2Fd4O/Ln1Tzfnk/dMLqxaNsXPw37nw+OUhycFDPPQF/ H4Q4+UDJ3ATf5Z2yQKkUQlD45OO2mIXjkWprAmOCi76dLB2yzhCX/plGJwcgb8XH EQIDAQAB -----END PUBLIC KEY-----將其復制到public.txt文件,并將其放置在/src/main/resources ,然后配置指向該文件的application.yml :
security:jwt:public-key: classpath:public.txt現(xiàn)在,讓我們?yōu)橘Y源服務器添加Spring的配置。
import org.apache.commons.io.IOUtils; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; 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; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;import java.io.IOException;import static java.nio.charset.StandardCharsets.UTF_8;@Configuration @EnableResourceServer @EnableConfigurationProperties(SecurityProperties.class) public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {private static final String ROOT_PATTERN = "/**";private final SecurityProperties securityProperties;private TokenStore tokenStore;public ResourceServerConfiguration(final SecurityProperties securityProperties) {this.securityProperties = securityProperties;}@Overridepublic void configure(final ResourceServerSecurityConfigurer resources) {resources.tokenStore(tokenStore());}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(HttpMethod.GET, ROOT_PATTERN).access("#oauth2.hasScope('read')").antMatchers(HttpMethod.POST, ROOT_PATTERN).access("#oauth2.hasScope('write')").antMatchers(HttpMethod.PATCH, ROOT_PATTERN).access("#oauth2.hasScope('write')").antMatchers(HttpMethod.PUT, ROOT_PATTERN).access("#oauth2.hasScope('write')").antMatchers(HttpMethod.DELETE, ROOT_PATTERN).access("#oauth2.hasScope('write')");}@Beanpublic DefaultTokenServices tokenServices(final TokenStore tokenStore) {DefaultTokenServices tokenServices = new DefaultTokenServices();tokenServices.setTokenStore(tokenStore);return tokenServices;}@Beanpublic TokenStore tokenStore() {if (tokenStore == null) {tokenStore = new JwtTokenStore(jwtAccessTokenConverter());}return tokenStore;}@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setVerifierKey(getPublicKeyAsString());return converter;}private String getPublicKeyAsString() {try {return IOUtils.toString(securityProperties.getJwt().getPublicKey().getInputStream(), UTF_8);} catch (IOException e) {throw new RuntimeException(e);}}}此配置的重要部分是三個@Bean : JwtAccessTokenConverter , TokenStore和DefaultTokenServices :
- JwtAccessTokenConverter使用JKS public key 。
- JwtTokenStore使用JwtAccessTokenConverter讀取令牌。
- DefaultTokenServices使用JwtTokenStore來保留令牌。
一起測試
為了一起測試,我們需要同時旋轉Authorization Server和Resource Server ,在我的設置中,它將相應地在端口9000和9100上運行。
生成令牌
$ curl -u clientId:secret -X POST localhost:9000/oauth/token\?grant_type=password\&username=user\&password=pass{"access_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDgxODk0NDUsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjFjYWQ3MTktZTkwMS00Njk5LTlhOWEtYTIwYzk2NDM5NjAzIiwiY2xpZW50X2lkIjoiY2xpZW50SWQiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.LkQ3KAj2kPY7yKmwXlhIFaHtt-31mJGWPb-_VpC8PWo9IBUpZQxg76WpahBJjet6O1ICx8b5Ab2CxH7ErTl0tL1jk5VZ_kp66E9E7bUQn-C09CY0fqxAan3pzpGrJsUvcR4pzyzLoRCuAqVRF5K2mdDQUZ8NaP0oXeVRuxyRdgjwMAkQGHpFC_Fk-7Hbsq2Y0GikD0UdkaH2Ey_vVyKy5aj3NrAZs62KFvQfSbifxd4uBHzUJSkiFE2Cx3u1xKs3W2q8MladwMwlQmWJROH6lDjQiybUZOEhJaktxQYGAinScnm11-9WOdaqohcr65PAQt48__rMRi0TUgvsxpz6ow","token_type" : "bearer","refresh_token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sImF0aSI6ImIxY2FkNzE5LWU5MDEtNDY5OS05YTlhLWEyMGM5NjQzOTYwMyIsImV4cCI6MTU1MDc4MTE0NSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6Ijg2OWFjZjM2LTJiODAtNGY5Ni04MzUwLTA5NTgyMzE3NTAzMCIsImNsaWVudF9pZCI6ImNsaWVudElkIn0.TDQwUNb627-f0-Cjn1vWZXFpzZSGpeKZq85ivA9zY_atOXM2WfjOxTLE6phnNLevjLSNAGrx1skm_sx6leQlrrmDi36nwiR7lvhv8xMbn1DkF5KaoWPhldW7GHsSIiauMu_cJ5Kmq89ZOEOlxYoXlLwfWYo75ISkKNYqko98yDogGrRAJxtc1aKIBLypLchhoCf8w43efd11itwvBdaLIb5ACfN30kztUqQtbeL8voQP6tOsRZbCgbOOKMTulOCRyBvaora4GJDV2qdvXdCUT-kORKDj9liqt2ae7OJzb2FuuXCGqBUrxYYK-H-wdwh7XFkXVe74Lev9YDUbyEmDHg","expires_in" : 299,"scope" : "read write","jti" : "b1cad719-e901-4699-9a9a-a20c96439603" }訪問資源
既然已經生成了令牌,請復制access_token并將其添加到Authorization HTTP Header上的請求中,例如:
curl localhost:9100/me -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDgxODk0NDUsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjFjYWQ3MTktZTkwMS00Njk5LTlhOWEtYTIwYzk2NDM5NjAzIiwiY2xpZW50X2lkIjoiY2xpZW50SWQiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.LkQ3KAj2kPY7yKmwXlhIFaHtt-31mJGWPb-_VpC8PWo9IBUpZQxg76WpahBJjet6O1ICx8b5Ab2CxH7ErTl0tL1jk5VZ_kp66E9E7bUQn-C09CY0fqxAan3pzpGrJsUvcR4pzyzLoRCuAqVRF5K2mdDQUZ8NaP0oXeVRuxyRdgjwMAkQGHpFC_Fk-7Hbsq2Y0GikD0UdkaH2Ey_vVyKy5aj3NrAZs62KFvQfSbifxd4uBHzUJSkiFE2Cx3u1xKs3W2q8MladwMwlQmWJROH6lDjQiybUZOEhJaktxQYGAinScnm11-9WOdaqohcr65PAQt48__rMRi0TUgvsxpz6ow"{"authorities" : [ {"authority" : "ROLE_GUEST"} ],"details" : {"remoteAddress" : "127.0.0.1","sessionId" : null,"tokenValue" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDgyMzcxNDEsInVzZXJfbmFtZSI6Imd1ZXN0IiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9HVUVTVCJdLCJqdGkiOiIzNDk1ODE1MC0wOGJkLTQwMDYtYmNhMC1lM2RkYjAxMGU2NjUiLCJjbGllbnRfaWQiOiJjbGllbnRJZCIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdfQ.WUwAh-aKgh_Bqk-a9ijw67EI6H8gFrb3D_WdwlEcITskIybhacHjT6E7cUXjdBT7GCRvvJ-yxzFJIQyI6y0t61SInpqVG2GlAwtTxR5reG0e4ZtcKoq2rbQghK8hWenGplGT31kjDY78zZv-WqCAc0-MM4cC06fTXFzdhsdueY789lCasSD4WMMC6bWbN098lHF96rMpCdlW13EalrPgcKeuvZtUBrC8ntL8Bg3LRMcU1bFKTRAwlVxw1aYyqeEN4NSxkiSgQod2dltA-b3c15L-fXoOWNGnPB68hqgK48ymuemRQTSg3eKmHFAQdDL6pxQ8_D_ZWAL3QhsKQVGDKg","tokenType" : "Bearer","decodedDetails" : null},"authenticated" : true,"userAuthentication" : {"authorities" : [ {"authority" : "ROLE_GUEST"} ],"details" : null,"authenticated" : true,"principal" : "guest","credentials" : "N/A","name" : "guest"},"credentials" : "","principal" : "guest","clientOnly" : false,"oauth2Request" : {"clientId" : "clientId","scope" : [ "read", "write" ],"requestParameters" : {"client_id" : "clientId"},"resourceIds" : [ ],"authorities" : [ ],"approved" : true,"refresh" : false,"redirectUri" : null,"responseTypes" : [ ],"extensions" : { },"grantType" : null,"refreshTokenRequest" : null},"name" : "guest" }腳注
- 本教程使用的代碼可以在GitHub上找到
- OAuth 2.0
- Spring Security Java配置預覽
- Spring Boot 2 –遷移指南
- Spring– OAuth2開發(fā)人員指南
翻譯自: https://www.javacodegeeks.com/2019/03/centralized_-authorization_-oauth2_jwt.html
總結
以上是生活随笔為你收集整理的使用Spring Boot 2通过OAuth2和JWT进行集中授权的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓不能安装app怎么解决(安卓不能安装
- 下一篇: 使用Spring Boot和MongoD