oauth2. Detailed explanation of 0 authorization code mode

Posted by MishaPappa on Mon, 07 Mar 2022 14:15:50 +0100

oauth2.0 authorization code mode

Welcome to the "Java master" of the blogger official account, focusing on dry cargo articles in Java field. http://www.javaman.cn/sb2/oauth-code

Authorization code means that a third-party application first applies for an authorization code, and then uses the code to obtain a token.

This method is the most commonly used process and has the highest security. It is suitable for Web applications with back-end. The authorization code is transmitted through the front end, the token is stored in the back end, and all communication with the resource server is completed in the back end. This separation of front and rear ends can avoid token leakage.

1. Authorization code mode process

In the first step, website A provides A link. After clicking, the user will jump to website B and authorize the user data to website A. The following is A schematic link from website A to website B.

https://b.com/oauth/authorize?
  response_type=code&
  client_id=CLIENT_ID&
  redirect_uri=CALLBACK_URL&
  scope=read

In the above URL, response_ The type parameter indicates that it is required to return the authorization code, client_ The ID parameter lets B know who is requesting and redirect_ The URI parameter is the jump URL after B accepts or rejects the request, and the scope parameter indicates the required authorization range (read-only here).

Step 2: after the user jumps, website B will ask the user to log in, and then ask whether he agrees to grant authorization to website A. When the user agrees, website B will jump back to redirect_ The URL specified by the URI parameter. When jumping, an authorization code will be returned, as shown below.

https://a.com/callback?code=AUTHORIZATION_CODE

In the above URL, the code parameter is the authorization code.

Third, after website A gets the authorization code, it can request A token from website B at the back end.

https://b.com/oauth/token?
 client_id=CLIENT_ID&
 client_secret=CLIENT_SECRET&
 grant_type=authorization_code&
 code=AUTHORIZATION_CODE&
 redirect_uri=CALLBACK_URL

In the above URL, client_id parameter and client_ The secret parameter is used to let B confirm the identity of A (the client_secret parameter is confidential, so it can only send requests at the back end). Grant_ The value of the type parameter is AUTHORIZATION_CODE indicates that the authorization method adopted is the authorization code, and the code parameter is the authorization code obtained in the previous step, redirect_ The URI parameter is the callback URL after the token is issued.

Step 4: after receiving the request, website B will issue a token. The specific method is to report to redirect_uri to send a piece of JSON data.

{    
  "access_token":"ACCESS_TOKEN",
  "token_type":"bearer",
  "expires_in":2592000,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"read",
  "uid":100101,
  "info":{...}
}

In the JSON data above, access_ The token field is the token. Website A gets it at the back end.

2. Authorization code mode implementation code

2.1 create POM xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dashi</groupId>
    <artifactId>springsecurity-oauth</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springsecurity-oauth</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR5</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <!--security rely on-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <!--boot rely on-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--boot rely on-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--test rely on-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

2.2 create spring security configuration file

package com.dashi.springsecurityoauth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/oauth/**","/login/**","/logout/**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll();
    }
}

2.3 create UserService and implement UserDetailService interface

package com.dashi.springsecurityoauth.model;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;

public class User implements UserDetails {
    private String username;
    private String password;
    private List<GrantedAuthority> authorities;

    public User(String username, String password, List<GrantedAuthority> authorities) {
        this.username = username;
        this.password = password;
        this.authorities = authorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

2.4 creating authentication services

package com.dashi.springsecurityoauth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("admin")
                .secret(passwordEncoder.encode("654321"))
                .accessTokenValiditySeconds(3600)
                .redirectUris("http://www.baidu.com")
                .scopes("all")
                //Configure grant_type indicates authorization code
                .authorizedGrantTypes("authorization_code");
    }
}

2.5 creating resource services

package com.dashi.springsecurityoauth.config;

import org.springframework.context.annotation.Configuration;
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 ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .requestMatchers()
          		//Addresses starting with / user access resources according to the token
                .antMatchers("/user/**");
    }
}

2.6 start service access address

http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all

2.7 in the previous step, the connection jumps to the input user name and address


2.8 click the resources allowed to be accessed and jump to the authorized website( http://www.baidu.com ), get authorization code

2.9 open postman, fill in the following contents and get the token

2.10 accessing protected resources through token

Reference documents: Four ways of OAuth 2.0 - ruanyifeng's Weblog (ruanyifeng.com)

Topics: spring-security