preface

Article content output source: Pull hook education Java high salary training camp;

There are two main forms of unified authentication in microservice architecture:

1. Session-based authentication in a distributed environment, session-based authentication has a problem. Each application service needs to store user identity information in the Session. Otherwise, recertification will occur. We can use Session sharing, Session sticky, etc. The Session scheme also has disadvantages, such as cookie-based and ineffective use on mobile devices

2. Token-based authentication. Tok-based authentication allows the server to avoid storing authentication data, which is easy to maintain and scalable. The client can store the token anywhere, and the authentication mechanism can be unified between the Web and APP. The disadvantages of token are also obvious. Because token contains self-contained information, the amount of data is generally large. In addition, each request needs to be transmitted, so it consumes more bandwidth. In addition, the token signature verification operation will also bring additional processing burden to the CPU.

The following is the token-based authentication. Using OAuth2 framework to achieve.

OAuth2 open licensing agreements/standards

OAuth (Open Authorization) is an open protocol/standard that allows users to authorize third party applications to access their information stored on another service provider without having to provide a user name and password to third party applications or share all the content of their data. Allows users to authorize third-party applications to access their information stored on another service provider without having to provide the user name and password to the third-party application or share all the content of their data.

The flow chart of OAuth2 protocol is as follows:

image-20200820205533344

1. The client requests user authorization

2. The user confirms authorization

3. After receiving the authorization, the client applies for a token from the authentication server

4. The authentication server verifies the license and returns a valid token to the client

5. The client carries a valid token to access the resource server

6. The resource server verifies the valid token from the authentication server.

7. After the authentication succeeds, return the corresponding resources to the client.

When should OAuth2 be used?

Third party authorized login scenario: For example, when we often log in to some websites or applications, we can choose to use the third party authorized login mode, such as wechat authorized login, QQ authorized login, Weibo authorized login, etc., which is a typical OAuth2 use scenario. Single sign-on scenario: If there are many micro-services in the project or many services in the company, you can set up a special authentication center (acting as the authentication platform), and all the services need to be authenticated by this authentication center. Only one login can be done, and the services within the scope of multiple authorization can be serialized freely.

Spring Cloud OAuth2 + JWT implementation

Spring Cloud OAuth2 is the implementation of OAuth2 protocol in Spring Cloud system, which can be used to do unified authentication (verify identity legitimacy) authorization (verify permission) of multiple micro-services. Centralized authentication and authorization is achieved by sending some type of Grant_type to the OAuth2 service (Unified Authentication and Authorization Service) to obtain an Access_token that is trusted by other microservices.

The essence of using OAuth2 to solve the problem is to introduce an authentication and authorization layer that connects to the owner of the resource. In the authorization layer, the owner of the resource can grant third-party applications access to some of our protected resources.

Setting up an Authentication Server

Create a new module, service-oauth-HW-9900.

Rely on

The poM file has the following dependencies:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

<dependency>  <groupId>org.springframework.security.oauth.boot</groupId>  <artifactId>spring-security-oauth2-autoconfigure</artifactId> < version > 2.1.11. RELEASE < / version ></dependency> <! Security support for oauth2 --><dependency>  <groupId>org.springframework.security.oauth</groupId>  <artifactId>spring-security-oauth2</artifactId> < version > 2.3.4. RELEASE < / version ></dependency>  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> Copy the code

The configuration file

server:
  port: 9900
spring:
  application:
    name: service-oauth-hw
 zipkin: Base - url: http://127.0.0.1:8771# zipkin server request address  sender:  The Web client sends trace log data to the server via a network request, plus configuration  # Kafka/Rabbit client passes trail log data to MQ for relay  type: web  sleuth:  sampler:  Sampling rate 1 means 100% of all data will be collected. By default, 0.1 means 10% of the requested trace data will be collected  # In the production environment, the number of requests is very large, so it is not necessary to collect and analyze the trace data of all requests. As the pressure of network including server side is relatively large, you can configure the sampling rate to collect a certain proportion of the trace data of requests for analysis  probability: 1 eureka:  client:  serviceUrl: Path to eureka Server  defaultZone: http://quellanan.a:8761/eureka/,http://quellanan.b:8762/eureka/ Eureka server can synchronize the registry with each eureka server  instance:  prefer-ip-address: true Register with IP  # Distributed link tracing logging:  level:  org.springframework.web.servlet.DispatcherServlet: debug  org.springframework.cloud.sleuth: debug  Copy the code

Start the class

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceOauthHw9900Application {

    public static void main(String[] args) {
 SpringApplication.run(ServiceOauthHw9900Application.class, args);  }  } Copy the code

config

Customize an OauthServerConfiger. The current class for Oauth2 server configuration class (we need to inherit certain superclass AuthorizationServerConfigurerAdapter)

@Configuration
@ EnableAuthorizationServer / / open authentication server capabilitiespublic class OauthServerConfiger extends AuthorizationServerConfigurerAdapter {


 @Autowired  private AuthenticationManager authenticationManager;  / * ** Customer review configuration,* For example client_id, secret* At present, this service is just like QQ platform. As a client, The QQ platform is required for login authorization and authentication. You need to register on THE QQ platform in advance, and the QQ platform will give the service to The QQ platform* Issue necessary parameters such as client_id to indicate who the client is * @param clients  * @throws Exception * / @Override  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {  super.configure(clients); Where is the client information stored, either in memory or in a database clients.inMemory() // Add a client configuration specifying its client_id .withClient("quellanan") // Specify the client password/security code .secret("abcdefg") // Specify a list of resource ids that can be accessed by the client. The resource ids must be configured on a specific resource server .redirectUris("*") // The authentication type/token issuing mode can be configured here, but not all of them can be used. The specific way to issue tokens needs to be specified when the client calls .authorizedGrantTypes("password"."refresh_token") // Client permission range. Set this parameter to all .scopes("all");  }    / * ** Authentication server ultimately provides services in the form of API interface (verify validity and generate tokens, verify tokens, etc.)* Then, using the API interface to external, it involves the interface access permission, we need to do the necessary configuration here * @param security  * @throws Exception * / @Override  public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {  super.configure(security);  // Turn on endPoints so that we can access the interface later security // Allow client form authentication .allowFormAuthenticationForClients() // enable port /oauth/token_key access permission (allow) .tokenKeyAccess("permitAll()") // enable port /oauth/check_token access permission (allowed) .checkTokenAccess("permitAll()");  }    @Override  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {  super.configure(endpoints);   endpoints // Specify the token storage method .tokenStore(tokenStore()) // A description of the token service, which can be thought of as a description of the token generation details, such as the validity period, etc .tokenServices(authorizationServerTokenServices()) // Specify the authentication manager and inject one into the current class .authenticationManager(authenticationManager)  .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);    }  / *This method is used to create a tokenStore object (tokenStore object)In what form are tokens stored* / public TokenStore tokenStore() { return new InMemoryTokenStore(); // Use the JWT token //return new JwtTokenStore(jwtAccessTokenConverter());  }   / * ** This method allows the user to obtain a token service object (which describes the token validity period and other information).* / public AuthorizationServerTokenServices authorizationServerTokenServices() { // Use the default implementation DefaultTokenServices defaultTokenServices = new DefaultTokenServices();  defaultTokenServices.setSupportRefreshToken(true); // Whether to enable token refresh defaultTokenServices.setTokenStore(tokenStore());  // Add for JWT token //defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());  // Set the token validity period (usually set to 2 hours)defaultTokenServices.setAccessTokenValiditySeconds(20); // Access_token is the token we need to carry when requesting resources// Set the validity time for refreshing the tokendefaultTokenServices.setRefreshTokenValiditySeconds(259200); / / 3 days  return defaultTokenServices;  } } Copy the code

About the three configure methods

  • Configure (ClientDetailsServiceConfifigurer clients) : This is used to configure the ClientDetailsService, where the client details are initialized and where you can write the client details or store the details from the database

  • Confifigure (AuthorizationServerEndpointsConfifigurer endpoints) : used to configure the access token (token) endpoint and token service (token services)

  • Confifigure (AuthorizationServerSecurityConfifigurer oauthServer) : used to configure the token endpoint security constraints.

About TokenStore

  • InMemoryTokenStore is used by default, it works perfectly on a single server (i.e. there is little pressure to access concurrency and it does not take a backup in case of failure), most projects can be tried with this version of the implementation, you can use it to manage at development time, It is easier to debug because it is not saved to disk.

  • JdbcTokenStore This is a JDBC-based implementation version where tokens are stored in a relational database. With this version of the implementation, you can share token information between different servers, and be sure to add the “SpringJDBC” dependency to your classpath. JwtTokenStore, which stands for JSON Web Token (JWT), encodes token-related data (so it doesn’t need to be stored for back-end services, which would be a big advantage). The downside is that this Token takes up a lot of space. If you add multiple user credentials, JwtTokenStore does not store any data.

Then there is a custom configuration class, which mainly deals with the verification of user names and passwords.

@Configuration
public class SecurityConfiger extends WebSecurityConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;
  //@Autowired  //private JdbcUserDetailsService jdbcUserDetailsService;  / * ** Register an authentication manager object to the container* / @Bean  @Override  public AuthenticationManager authenticationManagerBean() throws Exception {  return super.authenticationManagerBean();  }   / * ** Password encoding object (passwords are not encrypted) * @return * / @Bean  public PasswordEncoder passwordEncoder() {  return NoOpPasswordEncoder.getInstance();  }  / * ** Handle username and password authentication* 1) The client passes username and password parameters to the authentication server* 2) In general, username and password are stored in the user table in the database* 3) Verify the validity of the user information currently transmitted according to the data in the user table* / @Override  protected void configure(AuthenticationManagerBuilder auth) throws Exception { // In this method, we can disassociate the database. For now, we can configure the user information in memory// Instantiate a user object (equivalent to a user record in a data table) UserDetails user = new User("admin"."123456",new ArrayList<>());  auth.inMemoryAuthentication()  .withUser(user).passwordEncoder(passwordEncoder);   //auth.userDetailsService(jdbcUserDetailsService).passwordEncoder(passwordEncoder);  } } Copy the code

JWT revamps the token storage mechanism of the Unified Certification and Authorization Center

JWT token introduction

Through the above test, we found that when resource service and authorization service are not together, resource service uses RemoteTokenServices to remotely request authorization service to verify token. If the number of visits is large, the system performance will be affected.

Solve the above problems: Token by JWT format can solve the above problems, the user authentication through a JWT will get tokens, JWT is included in the token user related information, the client only need to carry JWT access resources service, resource service according to the predetermined algorithm itself token check, without having to request certification service every time to complete the authorization.

What is JWT?

JSON Web Token (JWT) is an open industry standard (RFC 7519) that defines a brief, self-contained protocol format for transferring JSON objects between communication parties that can be digitally signed to be verified and trusted. JWT can be signed using the HMAC algorithm or using RSA’s public/private key pair to prevent tampering.

JWT token structure

The JWT token consists of three parts, each with a dot (.) in the middle. Separate, for example: xxXXX.yyyyy.zzzzz

  • The Header. The header includes the type of token (that is, JWT) and the hash algorithm used (such as HMAC SHA256 or RSA), for example

    {
     "alg": "HS256". "typ": "JWT"
    }
    Copy the code

Encoding the above content using Base64Url to get a string is the first part of the JWT token.

  • Payload. The second part is the payload, which is also a JSON object that holds valid information. It can hold off-the-shelf fields provided by JWT, such as ISS (signer), EXP (expiration timestamp), sub (user-oriented), and so on, as well as custom fields. This section is not recommended for storing sensitive information because it can be decoded to restore the original content. Finally, the second part of the payload is encoded using Base64Url, resulting in a string that is the second part of the JWT token. An example:

    {
     "sub": "1234567890". "name": "John Doe". "iat": 1516239022
    }
    Copy the code
  • Signature. The third part is the signature, which is used to prevent JWT content from being tampered with. This part encodes the first two parts using base64URL, using the dot (.). The connection is a string, and the signature algorithm is declared in the header.

    HMACSHA256(
     base64UrlEncode(header) + "." +
     base64UrlEncode(payload),
     secret)
    Copy the code

    Base64UrlEncode (header) : The first part of the JWT token.

    Base64UrlEncode (Payload) : The second part of the JWT token.

    Secret: indicates the key used for signing.

Authentication server side JWT modification (Modification master configuration class)

/ *This method is used to create a tokenStore object (tokenStore object)In what form are tokens stored* /public TokenStore tokenStore() { //return new InMemoryTokenStore(); // Use the JWT token return new JwtTokenStore(jwtAccessTokenConverter()); }  / * ** Returns the JWT token converter (which helped us generate the JWT token)* Here, we can pass in the signing key to the converter object* @return * /public JwtAccessTokenConverter jwtAccessTokenConverter() {  JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); jwtAccessTokenConverter.setSigningKey(sign_key); // Signature keyjwtAccessTokenConverter.setVerifier(new MacSigner(sign_key)); // The key used for authentication must be the same as the signature key jwtAccessTokenConverter.setAccessTokenConverter(lagouAccessTokenConvertor);  return jwtAccessTokenConverter; } Copy the code

Modify the JWT token service method

/ * ** This method allows the user to obtain a token service object (which describes the token validity period and other information).* /public AuthorizationServerTokenServices authorizationServerTokenServices() {
// Use the default implementation DefaultTokenServices defaultTokenServices = new DefaultTokenServices();  defaultTokenServices.setSupportRefreshToken(true); // Whether to enable token refresh defaultTokenServices.setTokenStore(tokenStore());  // Add for JWT token defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());  // Set the token validity period (usually set to 2 hours)defaultTokenServices.setAccessTokenValiditySeconds(20); // Access_token is the token we need to carry when requesting resources// Set the validity time for refreshing the tokendefaultTokenServices.setRefreshTokenValiditySeconds(259200); / / 3 days  return defaultTokenServices; } Copy the code

conclusion

In our actual work, token authentication is very common. Now, this set of solutions can also be directly used in the project, friends, hurry to learn.

This article is formatted using MDNICE