@[TOC](OAuth2.0 Series authorization Code Practice tutorial (II))

OAuth2.0 series of blogs:

  • Basic Concept and Operation Process of OAuth2.0 Series (1)
  • OAuth2.0 Authorization Mode Tutorial (part 2)
  • OAuth2.0 Simplified Mode Tutorial (Part 3)
  • OAuth2.0 Series of Password mode practice tutorial (4)
  • OAuth2.0 Client Mode Tutorial (5)
  • OAuth2.0 Series information database storage tutorial (6)
  • OAuth2.0 Redis Information Storage Tutorial (7)
  • OAuth2.0 JWT Token Tutorial (8)
  • OAuth2.0 series integrated JWT for single sign-on

1. Introduction to authorization code mode

1.1 Introduction

In the last article we learned some basic concepts of OAuth2, have a basic understanding of OAuth2, then study the authorization code pattern in OAuth2.0 authorization mode

Ps: OAuth2.0 authorization mode can be divided into:

  • Authorization Code
  • Simplified patterns (Implicit)
  • Password mode (Resource owner Password Credentials)
  • Client credentials

In authorization Code mode, a third-party application first applies for an authorization code and then obtains a token using the code. Authorization code mode The authorization mode with the most complete functions, most widely used, and most rigorous procedures

1.2 Authorization Flow Chart

Official website photo:

  • (A) : The client carries client_id and redirect_URI and accesses the authorization server through the proxy. If the client has logged in to the authorization server, redirect_URI will be returned directly. If the client has not logged in to the authorization server, the login page will be redirected
  • (B) Authorize the server to authenticate the client (through the user agent, allowing the user to enter a username and password)
  • (C) If the authorization passes, it will be redirected to redirect_URI and carry the authorization code as the URI parameter
  • (D) The client carries the authorization code to access the authorization server
  • (E) Verify the authorization code and return the acceptToken

In terms of tuning interface, simply put:

  • Obtain code: eg: oauthServer+”/oauth/authorize? Client_id =”+clientId+”&response_type=code&redirect_uri=”+redirectUrl+”&scope=all” If no login is performed, the unified authentication login page is redirected. If the user is logged in and calls the interface, it is redirected to redirect_URI with the authorization code as its argument

  • Step 2: Obtain access_token eg: oauthServer+”/oauth/token? code=”+code+”&grant_type=authorization_code&client_secret=”+clientSecret+”&redirect_uri=”+redirectUri+”&client_id=”+clie ntId

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODk1MzQ5NzMsInVzZXJfbmFtZSI6Im5pY2t5IiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9hZG 1pbiJdLCJqdGkiOiJmMjM0M2Q0NC1hODViLTQyOGYtOWE1ZS1iNTE4NTAwNTM5ODgiLCJjbGllbnRfaWQiOiJvYSIsInNjb3BlIjpbImFsbCJdfQ.LWkN2gC 2dBrGTn5uSPzfdW6yRj7jhlX87EE8scY02hI"."token_type": "bearer"."expires_in": 59."scope": "all"."user_name": "nicky"."jti": "f2343d44-a85b-428f-9a5e-b51850053988"
}
Copy the code
  • Step 3: Access system resources. The unified authentication service determines whether to return the information based on the permission information of the authentication client.

Visit: http://localhost:8084/api/userinfo? access_token=${accept_token}

2. Examples and practices

2.1 Preparation of the experimental environment

  • IntelliJ IDEA
  • Maven3.+ Creates a SpringBoot Initializer project, which can be named authorization_code

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 <! -- Spring Cloud Oauth2-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <! -- Spring Cloud Security-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
Copy the code

2.2 OAuth2.0 role

From the previous study, we know that OAuth2.0 mainly includes the following roles. The following code examples deepen the understanding of the theory

  • Resource Owner
  • User Agent
  • The Client (Client)
  • Authorization Server
  • Resource Server

Production, resource, and authorization servers are typically kept separate, but learning can be kept together

Define the resource server with the @enableresourceserver annotation; Define authorization server, use annotations @ EnableAuthorizationServer;

2.3 OAuth2.0 configuration class

package com.example.springboot.authorizationcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;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.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;


/** ** <pre> * OAuth2.0 configuration class * </pre> ** <pre> *@authorMazq * Modified Record * Modified by: Date: 2020/06/11 11:00 Modified Content: * </pre> */
@Configuration
// Enable the authorization service
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    private static final String CLIENT_ID = "cms";
    private static final String SECRET_CHAR_SEQUENCE = "{noop}secret";
    private static final String SCOPE_READ = "read";
    private static final String SCOPE_WRITE = "write";
    private static final String TRUST = "trust";
    private static final String USER ="user";
    private static final String ALL = "all";
    private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60;
    private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60;
    // Password mode Authorization mode
    private static final String GRANT_TYPE_PASSWORD = "password";
    // Authorization code mode
    private static final String AUTHORIZATION_CODE = "authorization_code";
    / / refresh token mode
    private static final String REFRESH_TOKEN = "refresh_token";
    // Simplify the authorization mode
    private static final String IMPLICIT = "implicit";
    // Specify which resources require authorization validation
    private static final String RESOURCE_ID = "resource_id";

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                // Use memory storage
                .inMemory()
                // Mark the client ID
                .withClient(CLIENT_ID)
                // Client security code
                .secret(SECRET_CHAR_SEQUENCE)
                // Return code for true direct automatic authorization success
                .autoApprove(true)
                .redirectUris("http://127.0.0.1:8084/cms/login") // Redirect the URI
                // Allow the scope of authorization
                .scopes(ALL)
                / / token time seconds
                .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
                // Refresh the token time in seconds
                .refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS)
                // Allowed authorization type
                .authorizedGrantTypes(AUTHORIZATION_CODE );
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // Use memory to store the generated token
        endpoints.authenticationManager(authenticationManager).tokenStore(memoryTokenStore());
    }

    /** * Authentication server security configuration **@param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                //.realm(RESOURCE_ID)
                // Enable /oauth/token_key authentication port permission access
                .tokenKeyAccess("isAuthenticated()")
                // Enable /oauth/check_token authentication port authentication permission access
                .checkTokenAccess("isAuthenticated()")
                // Allow form authentication
                .allowFormAuthenticationForClients();
    }

    @Bean
    public TokenStore memoryTokenStore(a) {
        // The most basic InMemoryTokenStore generates tokens
        return newInMemoryTokenStore(); }}Copy the code

2.4 Security Configuration Classes

To test, you can do simple SpringSecurity

package com.example.springboot.authorizationcode.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/ * * * < pre > * SpringSecurity configuration class * < / pre > < pre > * * *@authorMazq * Modified Record * Modified by: Date: 2020/06/11 11:23 Modified Content: * </pre> */
@Configuration
@EnableWebSecurity
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean(a) throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {    //auth.inMemoryAuthentication()
        auth.inMemoryAuthentication()
                .withUser("nicky")
                .password("{noop}123")
                .roles("admin");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // Resolve static resource interception
        web.ignoring().antMatchers("/asserts/**");
        web.ignoring().antMatchers("/favicon.ico");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http   // Configure the login page and allow access
                .formLogin().permitAll()
                // Configure Basic login
                //.and().httpBasic()
                // Configure the logout page
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
                .and().authorizeRequests().antMatchers("/oauth/**"."/login/**"."/logout/**").permitAll()
                // All other requests require authentication
                .anyRequest().authenticated()
                // Disable cross-domain protection;.and().csrf().disable(); }}Copy the code

2.5 Simple function test

Access can access authorization link, the browser, authorization code mode payload parameters transfer code: http://localhost:8888/oauth/authorize? client_id=cms&client_secret=secret&response_type=code

Because there is no login, the default login page for SpringSecurity is returned with http.formLogin ().permitall (); Http.httpbasic (); Http.formlogin ().loginPage(“/login”).permitall ()

As shown, enter the static account password for SpringSecurity configuration :nicky/123

Login successful, return to the redirect_uri, to get the authorization code http://127.0.0.1:8084/cms/login? code=lA4EAJ

Get the license code to get the token

{
    "access_token": "dcb626c2-e514-4a8c-8df1-90fe5b5baabf"."token_type": "bearer"."expires_in": 119."scope": "all"
}
Copy the code

Username = client_id and password = client_secret

Code request, can be encapsulated as follows, that is, base64 encryption

HttpHeaders headers = new HttpHeaders();
        byte[] key = (clientId+":"+clientSecret).getBytes();
        String authKey = new String(Base64.encodeBase64(key));
        LOG.info("Authorization:{}"."Basic "+authKey);
        headers.add("Authorization"."Basic "+authKey);
Copy the code

Example code download