The original address: https://blog.lanweihong.com/p…

OAuth is an authorization mechanism used to standardize Token issuance, which mainly includes four authorization modes: authorization code mode, simplified mode, password mode and client mode. For more information about OAuth, visit the Understanding OAuth 2.0 view. This paper mainly uses password mode to achieve user authentication and authorization.

Set up the project

The project code has been uploaded to GitHub.

This example project is based on micro-service, and only realizes authentication service and resource service, and omits others such as gateway, service management, configuration center, etc. This paper focuses on using Spring Security + OAuth 2.0 + JWT to realize user authentication and authorization.

The project structure is shown in the figure below. Authentication service and resource service are separated. Authentication service mainly provides token and verification token service.

The parent project pom.xml is configured as follows, mainly to specify the version of the dependent package:

<! - dependent package version management - > < properties > < project. Build. SourceEncoding > utf-8 < / project. Build. SourceEncoding > < spring. The boot. Version > 2.2.2. RELEASE < / spring. The boot. Version > < spring. Cloud. Version > Hoxton. SR9 < / spring. Cloud. Version > < spring cloud. Alibaba. Version > 2.2.1. RELEASE < / spring. Cloud. Alibaba. Version > < mysql. Driver. Version > 8.0.16 < / mysql. Driver. Version > < lombok. Version > 1.16.18 < / lombok version > </druid.version> </properties> <dependencyManagement> < Dependencies > <! -- spring boot 2.2.2.RELEASE --> <dependency> <groupId>org.springframework.boot</groupId> < artifactId > spring - the boot - dependencies < / artifactId > < version > 2.2.2. RELEASE < / version > < type > pom < type > <scope>import</scope> </dependency> <! -- spring cloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <! -- Spring Cloud Alibaba --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring.cloud.alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <! -- mysql driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.driver.version}</version> </dependency> <! -- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <! -- druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> </dependencies> </dependencyManagement>

Setting up certification services

Introduction of depend on

  1. inpom.xmlIntroduce the following dependencies:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-jose</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency>  <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>

Spring-cloud-starter-OAuth2 already includes Spring-cloud-starter-Security, Spring-security-OAuth2, and Spring-security-JWT dependencies. Simply introduce spring-cloud-starter-oauth2.

  1. The editorapplication.yml, add database connection parameters:
Spring: a datasource: type: com. Alibaba. Druid. Pool. DruidDataSource url: JDBC: mysql: / / 127.0.0.1:3307 / oauth_server? useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 1 druid: driver-class-name: com.mysql.cj.jdbc.Driver initial-size: 5 max-active: 50 max-wait: 60000 min-idle: 5

The preparatory work

  1. newUserDTOClasses that implementorg.springframework.security.core.userdetails.UserDetailsInterface;
/** * @author lanweihong [email protected] */ @Data public class UserDTO implements Serializable, UserDetails { private static final long serialVersionUID = 5538522337801286424L; private String userName; private String password; private Set<SimpleGrantedAuthority> authorities; public Collection<? extends GrantedAuthority> getAuthorities() { return this.authorities; } public String getPassword() { return this.password; } public String getUsername() { return this.userName; } public boolean isAccountNonExpired() { return true; } public boolean isAccountNonLocked() { return true; } public boolean isCredentialsNonExpired() { return true; } public boolean isEnabled() { return true; }}
  1. The new classUserDetailsServiceImplTo realizeorg.springframework.security.core.userdetails.UserDetailsServiceInterface for verifying user credentials.
@Service public class UserDetailsServiceImpl implements UserDetailsService { private PasswordEncoder passwordEncoder; @Autowired public void setPasswordEncoder(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @ Override public populated UserDetails loadUserByUsername (String username) throws UsernameNotFoundException {/ / TODO in the actual development, Please modify this query from the database... UserDTO user = new UserDTO(); user.setUserName(username); // The password is 123456, and the password is encrypted User. setPassword(PasswordenCoder. encode("123456")); return user; }}

The above user configuration is used for testing, any user name, but the password is 123456. In actual production, it must be changed to read the verification from the database.

Configure the authentication authorization server

  1. Create a new class OAuth2ServerConfig, Inheritance org. Springframework. Security. Oauth2. Config. The annotation. Web. The configuration. The AuthorizationServerConfigurerAdapter classes; Add annotations @ EnableAuthorizationServer on Oauth2ServerConfig class.

    The framework provides several default endpoints:

    • /oauth/authorize: Authorization Endpoint
    • /oauth/token: Gets the token endpoint
    • /oauth/confirm_access: User confirms the authorization endpoint
    • /oauth/check_token: Verifies the token endpoint
    • /oauth/error: Used to render an error in the authorization server
    • /oauth/token_key: Gets the JWT public key endpoint
  2. Inheritance AuthorizationServerConfigurerAdapter after class, we need to rewrite the following three methods to expand our requirements.

    • configure(ClientDetailsServiceConfigurer clients): Used to define and initialize client information
    • configure(AuthorizationServerEndpointsConfigurer endpoints): Used to define authorization token endpoints and services
    • configure(AuthorizationServerSecurityConfigurer security): Security constraints used to define token endpoints

Configure the client details

ClientDetailsServiceConfigurer is used to define or client based on JDBC stored in memory, the several important attributes are:

  • clientId: Client ID, required;
  • clientSecret: Client key;
  • authorizedGrantTypes: Client authorization type, yes5Pattern:authorization_code,password,client_credentials,implicit,refresh_token;
  • scope: scope of authorization;
  • accessTokenValiditySeconds:access_tokenValid time, in seconds, default is12Hours.
  • refreshTokenValiditySeconds:refresh_tokenValid time, in seconds, default is30Days;

Client-side information is usually stored in Redis or a database, in this case in MySQL; JDBC storage mode based on the need to create data tables, the official provides a table to build the SQL statement, can access schema.sql to obtain SQL;

  1. Create a table using the following SQL (for MySQL) :
CREATE TABLE `oauth_client_details`  (
  `client_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `resource_ids` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `client_secret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `authorized_grant_types` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `web_server_redirect_uri` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `access_token_validity` int(11) NULL DEFAULT NULL,
  `refresh_token_validity` int(11) NULL DEFAULT NULL,
  `additional_information` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `autoapprove` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  1. Add a client message for testing:
INSERT INTO `oauth_client_details` VALUES ('auth-server', NULL, '$2a$10$mcEwJ8qqhk2DYIle6VfhEOZHRdDbCSizAQbIwBR7tTuv9Q7Fca9Gi', 'all', 'password,refresh_token', '', NULL, NULL, NULL, NULL, NULL);

After 123456 password using BCryptPasswordEncoder encryption, encryption for $2 a $10 $McEwJ8qqhk2DYIle6VfhEOZHRdDbCSizAQbIwBR7tTuv9Q7Fca9Gi characters.

  1. configurationClientDetailsServiceConfigurer, specify the client information:
@Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {  private final DataSource dataSource; private final PasswordEncoder passwordEncoder; @Autowired public Oauth2ServerConfig(DataSource dataSource, PasswordEncoder passwordEncoder) { this.dataSource = dataSource; this.passwordEncoder = passwordEncoder; } @ Override public void the configure (ClientDetailsServiceConfigurer clients) throws the Exception {/ / use based on JDBC stored pattern JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource); / / client_secret encryption clientDetailsService setPasswordEncoder (passwordEncoder); clients.withClientDetails(clientDetailsService); }}

Configure the authorization token endpoint and service

Configuration AuthorizationServerEndpointsConfigurer need to specify the AuthenticationManager and UserDetailService, especially when using password mode, AuthenticationManager must be specified, otherwise an Unsupported grant type: password error will be reported.

  1. newWebSecurityConfigClass, inheritance,org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapterClass, rewriteauthenticationManagerBean()Method and define the ones that need to be usedPasswordEncoder;
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // // Disable csrf.csrf ().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable() .authorizeRequests() .antMatchers("/oauth/token").permitAll(); .anyRequest().authenticated(); * * *} / rewrite authenticationManagerBean @ return () * * @ throws the Exception * / @ Override @ Bean public the AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}
  1. configurationAuthorizationServerEndpointsConfigurer:
@Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {  private final UserDetailsServiceImpl userDetailsService; /** * private final authenticationManager authenticationManager; /** * private final authenticationManager; @Autowired public Oauth2ServerConfig(UserDetailsServiceImpl userDetailsService, AuthenticationManager authenticationManager) { this.userDetailsService = userDetailsService; this.authenticationManager = authenticationManager; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints // AuthenticationManager (AuthenticationManager). UserDetailsService (UserDetailsService). }}
Use JWT as the token format
Generate the JWT key pair

Use the JDK’s keytool to generate the JKS key pair jwt. JKS, and place jwt. JKS in the resources directory.

Locate to the bin directory under the JDK directory, execute the following command to generate the key pair, remember the password key, the code needs the key to read the key pair, take 123456 as an example:

keytool -genkey -alias weihong -keyalg RSA -keypass 123456 -keystore jwt.jks -storepass 123456

Parameter description:

-genkey generate key -alias alias -keyalg key algorithm -keypass key password -keystore generate key pair store path and name -storepass key pair password
Define Token Converter

Define AccessStokenConverter () and keyPair() in the OAuth2ServerConfig class:

/** * Token converter * Default is UUID format, @bean public JWTAccessTokenConverter AccessTokenConverter () {public JWTAccessTokenConverter () {public JWTAccessTokenConverter () { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // Use asymmetric encryption to sign the token to Converter.setKeyPair (keyPair()); return converter; } @bean public KeyPair KeyPair () {// Get the secret KeyPair from the certificate jwt. JKS in the classpath directory and enter the password set in the generated KeyPair above: 123456, this is hard coded, KeystoreKeyFactory = new keystoreKeyFactory (new ClassPathResource("jwt. JKS ")), "123456".toCharArray()); return keyStoreKeyFactory.getKeyPair("weihong", "123456".toCharArray()); }
Specify the token storage policy as JWT

Configuration AuthorizationServerEndpointsConfigurer token storage strategy for JWT, designated accessTokenConverter as we defined accessTokenConverter () :

@Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {  private final UserDetailsServiceImpl userDetailsService; /** * private final authenticationManager authenticationManager; /** * private final authenticationManager; @Autowired public Oauth2ServerConfig(UserDetailsServiceImpl userDetailsService, AuthenticationManager authenticationManager) { this.userDetailsService = userDetailsService; this.authenticationManager = authenticationManager; } @ Override public void the configure (AuthorizationServerEndpointsConfigurer endpoints) {endpoints / / open authorization password mode .authenticationManager(authenticationManager).UserDetailsService (UserDetailsService) // Specifies the token storage policy .accessTokenConverter(accessTokenConverter()); } /** * Token converter * Default is UUID format, JWT * @Return */ @Bean public JWTAccessStokenConverter AccessStokenConverter () {JWTAccessStokenConverter () {JWTAccessStokenConverter  converter = new JwtAccessTokenConverter(); // Use asymmetric encryption to sign the token to Converter.setKeyPair (keyPair()); return converter; } @bean public KeyPair KeyPair () {// Get the secret key from the certificate jwt. JKS in the classpath directory to keystoreKeyFactory keystoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray()); return keyStoreKeyFactory.getKeyPair("weihong", "123456".toCharArray()); }}
Extend the JWT storage content

Sometimes you need to extend the contents of the JWT store, such as storing some user data, permission information, and so on. We can define a TokenEnhancer or inherit a TokenEnhancer to implement the JWT content enhancer:

@Bean public TokenEnhancer tokenEnhancer() { return (oAuth2AccessToken, oAuth2Authentication) -> { Map<String, Object> map = new HashMap<>(1); UserDTO userDTO = (UserDTO) oAuth2Authentication.getPrincipal(); map.put("userName", userDTO.getUsername()); / / TODO to add other information (DefaultOAuth2AccessToken oAuth2AccessToken). SetAdditionalInformation (map); return oAuth2AccessToken; }; }

Configuration AuthorizationServerEndpointsConfigurer JWT content enhancer:

@Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {  private final UserDetailsServiceImpl userDetailsService; private final AuthenticationManager authenticationManager; @Autowired public Oauth2ServerConfig(UserDetailsServiceImpl userDetailsService, AuthenticationManager authenticationManager) { this.userDetailsService = userDetailsService; this.authenticationManager = authenticationManager; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); List<TokenEnhancer> delegates = new ArrayList<>(); delegates.add(tokenEnhancer()); delegates.add(accessTokenConverter()); / / configuration JWT contents increase enhancerChain. SetTokenEnhancers (delegates); Endpoints // Enable password mode authorization. AuthenticationManager (AuthenticationManager). UserDetailsService (UserDetailsService) .accessTokenConverter(accessTokenConverter()) .tokenEnhancer(enhancerChain); } /** * Token converter * Default is UUID format, JWT * @Return */ @Bean public JWTAccessStokenConverter AccessStokenConverter () {JWTAccessStokenConverter () {JWTAccessStokenConverter  converter = new JwtAccessTokenConverter(); // Use asymmetric encryption to sign the token to Converter.setKeyPair (keyPair()); return converter; } @Bean public KeyPair keyPair() { KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray()); return keyStoreKeyFactory.getKeyPair("weihong", "123456".toCharArray()); } /** * JWT content enhancer, which extends JWT content, * @return */ @bean public TokenEnhancer TokenEnhancer () {return (OAuth2AccesToken, OAuth2AccesToken, oAuth2Authentication) -> { Map<String, Object> map = new HashMap<>(1); UserDTO userDTO = (UserDTO) oAuth2Authentication.getPrincipal(); map.put("userName", userDTO.getUsername()); / / TODO to add other information (DefaultOAuth2AccessToken oAuth2AccessToken). SetAdditionalInformation (map); return oAuth2AccessToken; }; }}
Use Redis to store tokens
  1. inpom.xmlAdd a dependency to:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. The editorapplication.yml, add Redis connection parameters:
spring:
  redis:
    host: localhost
    port: 6379
    password: 1
  1. Add token to save to Redis configuration:
@Configuration public class RedisTokenStoreConfig { @Resource private RedisConnectionFactory connectionFactory; @Bean public TokenStore redisTokenStore() { return new RedisTokenStore(connectionFactory); }}
  1. Specify how to store tokens in the authentication service configuration:
@Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {  private final UserDetailsServiceImpl userDetailsService; /** * private final authenticationManager authenticationManager; /** * private final authenticationManager; private final TokenStore tokenStore; @Autowired public Oauth2ServerConfig(UserDetailsServiceImpl userDetailsService, AuthenticationManager authenticationManager, @Qualifier("redisTokenStore") TokenStore tokenStore) { this.userDetailsService = userDetailsService; this.authenticationManager = authenticationManager; this.tokenStore = tokenStore; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints // AuthenticationManager (authenticationManager). UserDetailsService (UserDetailsService) // Set the token storage mode .tokenStore(tokenStore); }}

Configure authorization token security constraints

@ Override public void the configure (AuthorizationServerSecurityConfigurer security) throws the Exception {security / / allow forms authentication AllowFormAuthenticationForClients () / / open/request/token_key get public key token encryption. TokenKeyAccess (permitAll "()") / / open /oauth/check_token .checkTokenAccess("permitAll()"); }

Authentication authorization service configuration complete code

Oauth2ServerConfig:

@Configuration @EnableAuthorizationServer public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter { /** */ private final dataSource dataSource; private final UserDetailsServiceImpl userDetailsService; /** * private final authenticationManager authenticationManager; /** * private final authenticationManager; private final PasswordEncoder passwordEncoder; private final TokenStore tokenStore; @Autowired public Oauth2ServerConfig(DataSource dataSource, UserDetailsServiceImpl userDetailsService, AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, @Qualifier("redisTokenStore") TokenStore tokenStore) { this.dataSource = dataSource; this.userDetailsService = userDetailsService; this.authenticationManager = authenticationManager; this.passwordEncoder = passwordEncoder; this.tokenStore = tokenStore; } @ Override public void the configure (AuthorizationServerSecurityConfigurer security) {security / / allow forms authentication AllowFormAuthenticationForClients () / / must be certified before they can access/request/token_key get public key token encryption. TokenKeyAccess (permitAll "()") / / open /oauth/check_token .checkTokenAccess("permitAll()"); } @ Override public void the configure (ClientDetailsServiceConfigurer clients) throws the Exception {/ / use based on JDBC stored pattern JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource); clientDetailsService.setPasswordEncoder(passwordEncoder); clients.withClientDetails(clientDetailsService); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { TokenEnhancerChain enhancerChain =  new TokenEnhancerChain(); List<TokenEnhancer> delegates = new ArrayList<>(); delegates.add(tokenEnhancer()); delegates.add(accessTokenConverter()); / / configuration JWT contents increase enhancerChain. SetTokenEnhancers (delegates); Endpoints // Enable password mode authorization. AuthenticationManager (AuthenticationManager). UserDetailsService (UserDetailsService) .accesStokenConverter (AccesStokenConverter ()).tokenEnhancer(enhancerChain) // Set TokenStore.tokenStore (tokenStore); } /** * Token converter * Default is UUID format, JWT * @Return */ @Bean public JWTAccessStokenConverter AccessStokenConverter () {JWTAccessStokenConverter () {JWTAccessStokenConverter  converter = new JwtAccessTokenConverter(); // Use asymmetric encryption to sign the token to Converter.setKeyPair (keyPair()); return converter; } @Bean public KeyPair keyPair() { KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray()); return keyStoreKeyFactory.getKeyPair("weihong", "123456".toCharArray()); } /** * JWT content enhancer, which extends JWT content, * @return */ @bean public TokenEnhancer TokenEnhancer () {return (OAuth2AccesToken, OAuth2AccesToken, oAuth2Authentication) -> { Map<String, Object> map = new HashMap<>(1); UserDTO userDTO = (UserDTO) oAuth2Authentication.getPrincipal(); map.put("userName", userDTO.getUsername()); / / TODO to add other information (DefaultOAuth2AccessToken oAuth2AccessToken). SetAdditionalInformation (map); return oAuth2AccessToken; }; }}

WebSecurityConfig:

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // // Disable csrf.csrf ().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable().disable() .authorizeRequests() .antMatchers("/oauth/token").permitAll() .anyRequest().authenticated(); * * *} / rewrite authenticationManagerBean @ return () * * @ throws the Exception * / @ Override @ Bean public the AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}

Test Get Token

Access token

Run the project, use PostMan to access the /oauth/token endpoint, and pass the parameters. The parameters must be consistent with what we configured.

Token was successfully obtained in the following format:

{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTA1NjkzNDksInVzZXJOYW1lIjoiYWRtaW4iLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp0aS I6IjgzM2VjZDdkLThmMzctNDAxOS04YWQwLTBlODI3ZTM4M2U5YyIsImNsaWVudF9pZCI6Im9hdXRoLXNlcnZlciIsInNjb3BlIjpbImFsbCJdfQ.ke6fWfG MOXhppF-6XXftZJx0w8hSnTKYYwvi_As66Ats9_AFqrHCZiuHA_M5LD2bJzahFC__-IUr_6g6ajx-IlLpSPqs3izgbuOPcTzCivfznGn38W5kYPe1ygQ8mJz N97yAT1QKZGMAT0nr7HR5NSG2MHYPbHuWSHp4KVIf7XQbszmXVPKEeQsv64QZ8O1xe9XtshF4mtZsxfLEGxAZEPSkoyJi-vwH6qKnvVh8EI8zgwTX5cIh6Gj 4rcEfDiJYNAiI_NanuNA1wBoI1eD-QYSUQ5XXW1Q4vQAnjQMQwvTZYn1hGdAbeHQrA9hPLw5_Axeq8_meWpNobla_rRYkLQ", "token_type": "bearer", "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiI4MzNlY2Q3ZC04ZjM3LTQwMT ktOGFkMC0wZTgyN2UzODNlOWMiLCJleHAiOjE2MTMxMTgxNDksInVzZXJOYW1lIjoiYWRtaW4iLCJqdGkiOiIwMDljZjhmNy05OTE5LTQyODEtYjUxNS02Nj M3ZjIyM2MyN2YiLCJjbGllbnRfaWQiOiJvYXV0aC1zZXJ2ZXIifQ.bFMQRXCOz2rvu8QhTOjjlM66Fe3EM5F2wUXI-3dQOxnu2AOCsCJKUZdT0AhsnJkSI5E wc1jUd7TiUifj9p6CYzIuHtnPORUUE67vt7eiKjpdNdNaUIvXzSoAcx-B5FgYynKslZm5S6WwqQMEb6jFMeg1iN3DphDPbjUMCP2qZevm6fNTT0b7PzxE0PO epqqEnyjIS1YOnMnyHkgSAQCtYMAwWATalS4tMFNRb-hbE2MGi-U1j3Z1Mq79x9Uce8ZXjD2a_sCE9x0fqTixO-pRUrQNrIqiX_bZlw96xktnUQy2wCoJiZR xKjZyRhPLxOQPR7FUyd8yFXjCHR_yf5mwYw", "expires_in": 43199, "scope": "all", "userName": "admin", "jti": "833ecd7d-8f37-4019-8ad0-0e827e383e9c" }

Copy the returned token to https://jwt.io/ and parse it correctly.

Check token

  1. usePostmanaccess/oauth/check_tokenEndpoints, we’re trying to add errorstoken, and then send the request check, found that the return error;

  1. usePostmanaccess/oauth/check_tokenEndpoints, we use the correct onetokenVerify, return information on success;

The refresh token

Use PostMan to access the /oauth/token endpoint, where the parameter grant_type uses refresh_token, Refresh_token The content of refresh_token is the one we get from /oauth/token (note not access_token); Other parameters, please configure by yourself, please refer to the following:

Setting up resource services

  1. newmoduleIn thepom.xmlAdd a dependency to:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
  1. inapplication.ymlAdd the relevant parameters of token verification to theChange the token verification address to the token verification address of the authentication service:
Oauth2: resource - id: resource - server # token check address check - token - url: http://127.0.0.1:8089/oauth/check_token client - id: oauth-server client-secret: 123456

Configure resource services

  1. newResourceServerConfigClass, inheritance,org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter, add comments@EnableResourceServerAnd the configurationtokenCalibration service;
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Value("${oauth2.check-token-url}") private String checkTokenUrl; @Value("${oauth2.resource-id}") private String resourceId; @Value("${oauth2.client-id}") private String clientId; @Value("${oauth2.client-secret}") private String clientSecret; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId(resourceId).stateless(true); resources.tokenServices(resourceServerTokenServices()); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll() .anyRequest() .authenticated() .and() .requestMatchers() .antMatchers("/users/**"); } / configuration token validation service * * * * @ return * / @ Bean ResourceServerTokenServices ResourceServerTokenServices () {RemoteTokenServices  remoteTokenServices = new RemoteTokenServices(); remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl); remoteTokenServices.setClientId(clientId); remoteTokenServices.setClientSecret(clientSecret); remoteTokenServices.setAccessTokenConverter(accessTokenConverter()); return remoteTokenServices; } @Bean public AccessTokenConverter accessTokenConverter() { return new DefaultAccessTokenConverter(); }}
  1. Add the Controller
@RestController public class HomeController { @GetMapping("/users") public Map<String, Object> test(Authentication authentication) { Map<String, Object> data = new HashMap<>(1); data.put("user", authentication.getPrincipal()); return data; }}

test

Return unauthorised error for /users using Postman:

Postman access /users, with token access, successfully request and get the user data;

Project source address

https://github.com/lanweihong/spring-securuty-oauth2-jwt

Reference documentation

  1. Understand the 2.0
  2. OAuth 2 Developers Guide
  3. Spring Security OAuth2 custom token configuration