1. Create Maven project
(1) POM file
<?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.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cmxy</groupId> <artifactId>oauth2-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>oauth2-demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- Spring Security,OAuth2 and JWT Correlation dependency--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version> </dependency> <!--Web relevant--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!--Mysql Connection drive--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
(2) Project structure
2. Code implementation (only the simplest implementation for the time being, which will be supplemented later)
(1) Create authentication server configuration class
package com.cmxy.oauth2.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 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.stereotype.Component; /** * Authentication server configuration class * Role: configure which clients can access the currently configured server */ @Component @EnableAuthorizationServer //Mark as authentication server public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; /** * Configure client information that can access this authentication server * You can use JDBC or memory (the principle is not much different) * To facilitate the temporary use of memory based storage of client information */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory()//Memory based mode .withClient("client")//client ID .secret(passwordEncoder.encode("123456"))//The client secret key must be encrypted here. After spring security 5.0, the password must be encrypted. .resourceIds("product")//Accessible resource ID .scopes("user")//Accessible range //Authorization mode: that is, the authorization mode supported by the current authentication server in decibels is authorization code mode, password mode, client mode, simple mode and refresh Token .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token") .autoApprove(false)//Whether to authorize automatically. Generally, if it is set to false, it means that the user needs to authorize manually .redirectUris("www.baidu.com");//Redirect path } }
(2) Create Spring Security configuration class
package com.cmxy.oauth2.server.config; import org.springframework.beans.factory.annotation.Autowired; 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.crypto.password.PasswordEncoder; @EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password(passwordEncoder.encode("1234")) .authorities("product"); } }
(3) Configure the encryption method (after spring security 5.0, password encryption is required)
package com.cmxy.oauth2.server.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class SpringSecurityBean { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
3. Interface test
The first test is the authorization code mode
Authorization code mode:
The authorization mode with the most complete functions and the most rigorous process. Major domestic service providers (wechat, QQ, microblog, Taobao and Baidu) use this mode for authorization. It can be determined that the user really agrees to the authorization; Moreover, the token is issued by the authentication server to the server of the third-party application, not on the browser.
(1) Enter the url in the browser: http://localhost:8080/oauth/authorize?client_id=client&response_type=code
Including: client_id is configured in the configuration class, and the type of response is authorization code
(2) At this time, because you have not logged in before, you will jump to the landing page
Note that the account password here belongs to the resource owner, not the client!!! In this demo, the account is admin and the password is 123456
After successful login, jump to the authorization page (is it a little similar to wechat authorization)
(3) If you select authorization, you will jump to the previously configured redirection path, that is, Baidu
Note that the authorization code is included at this time. Finally, take the authorization code to replace the token. Each authorization code can only be used once.
(4) Get Token
Finally, carry the Token to request the corresponding resource. So far, the most complex authorization code mode has been completed
Unfinished to be continued...