The native OAuth2 dependencies provided by Spring come with several more commonly used authorization methods built in: Password, authorization-code, client_credentials, refresh_token, implicit, etc., can meet our daily needs, but we still have no choice for some special needs, such as: Wechat login, SMS login… To address this, ApiBoot modifies the source code that Spring OAuth2 relies on to customize grantType according to the business.

  • ApiBoot official documentation: apiboot.minbox.io

Create a project

We will use IDEA to create the project for this chapter. Pom.xml adds the following dependencies:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>  </dependency> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-security-oauth-jwt</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-starter-mybatis-enhance</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-dependencies</artifactId> <version> 2.2.2. RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>Copy the code

ApiBoot MyBatis Enhances the use of ApiBoot MyBatis Enhance.

The source code in this chapter is modified on the basis of the ApiBoot zero code integration of Spring Security JDBC access to AccessToken. Copy the application.yml, SystemUser, SystemUserEnhanceMppaer, and UserService files of the source code in previous chapters to the corresponding directories of the projects in this chapter.

Verification code login logic

This chapter describes how to use ApiBoot to customize the authorization mode for SMS verification code login.

In the SMS verification code login logic, the general process is as follows:

  1. When obtaining a verification code, the system saves the verification code in the database
  2. When a user enters a verification code and submits a login request, the user reads the verification code and checks its validity
  3. Finally, the user information corresponding to the mobile phone number is obtained to complete the login logic.
  4. Return the request token

According to the verification code login process to see the first thing we need to create a captcha data table, used to save users to send verification code data, through the mobile phone number is needed in step 3 to obtain the corresponding user information, so we have to modify before chapters create table structure, add a column, let’s begin.

Verification code table structure

Create a table named phone_code in the database and initialize a captcha data (simulating that the user has already sent the captcha), SQL as follows:

CREATE TABLE 'phone_code' (' pc_id 'int(11) NOT NULL AUTO_INCREMENT COMMENT '主键 increment ', 'pc_phone' varchar(11) COLLATE UTf8MB4_general_ci DEFAULT NULL COMMENT ' 'pc_code' varchar(6) COLLATE UTf8MB4_general_ci DEFAULT NULL COMMENT 'verification code content ', 'pc_create_time' TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'verification code generation time ', PRIMARY KEY (`pc_id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT=' id verification code '; INSERT INTO 'phone_code' VALUES (1,'17111111111','123123','2019-12-04 03:01:05');Copy the code

Captcha entity

Write a data entity corresponding to the phone_code table structure as follows:

/** * Phone number verification code information list ** @author */ @data@table (name = "phone_code") public class PhoneCode {/** * verification code primary key */ @Column(name = "pc_id") @Id(generatorType = KeyGeneratorTypeEnum.AUTO) private Integer id; /** * phone number */ @column (name = "pc_phone") private String phone; /** * verification code */ @column (name = "pc_code") private String code; /** * createTime */ @column (name = "pc_create_time") private Timestamp createTime; }Copy the code

Verification code data interface

Add a query data interface for PhoneCode captcha data entities to implement the EnhanceMapper interface provided by ApiBoot MyBatis Enhance, as shown below:

/** * public interface PhoneCodeEnhanceMapper extends EnhanceMapper<PhoneCode, Integer> {/** * queries the verification code of the mobile phone number ** @param phone {@link PhoneCode#getPhone()} * @param code {@link PhoneCode#getCode()} * @return {@link PhoneCode} */ PhoneCode findByPhoneAndCode(@Param("phone") String phone, @Param("code") String code); }Copy the code

Using the naming rule query syntax provided by ApiBoot MyBatis Enhance, we can query the corresponding records according to the specified phone and code.

Verification code business logic

Provide a business logic implementation class for captcha queries, as follows:

Service public class PhoneCodeService {/** * phone number verification code data interface */ @autoWired private PhoneCodeEnhanceMapper mapper; /** * query mobile phone verification code ** @param phone {@link PhoneCode#getPhone()} * @param code {@link PhoneCode#getCode()} * @return */ public PhoneCode findPhoneCode(String phone, String code) { return mapper.findByPhoneAndCode(phone, code); }}Copy the code

Modify the user table structure

We add a field to the system_user user table created in the AccessToken article, as follows:

Alter table system_user add su_phone varchar(11) NULL comment 'phone ';Copy the code

Initialize the column value of yuqiyu data in the table after the field is added. The phone number I added in the phone_code table is 17111111111, so I need to update the value of su_phone field to 17111111111.

Understand ApiBootOauthTokenGranter

The ApiBootOauthTokenGranter interface is a custom GrantType interface provided by ApiBoot OAuth2. The source code is shown as follows:

/** * ApiBoot Integrates Oauth2 to Realize Custom Authorization to Acquire Token ** @author: DateTime: 2019-05-28 09:57 * Blog: http://blog.yuqiyu.com * WebSite: http://www.jianshu.com/u/092df3f77bca * Gitee:https://gitee.com/hengboy * lot: https://github.com/hengboy */ public interface ApiBootOauthTokenGranter extends Serializable { /** * oauth2 grant type for ApiBoot * * @return grant type */ String grantType(); /** * load userDetails by parameter * * @param parameters parameter map * @return UserDetails * @throws ApiBootTokenException * @see UserDetails */ UserDetails loadByParameter(Map<String, String> parameters) throws ApiBootTokenException; }Copy the code

  • grantType(): The return value of this method is used to tellOAuth2The custom ofGrantTypeWhat it is depends on your business logic.
  • loadByParameter: This method is customGrantTypeBusiness implementation of,parametersParameter contains the custom authorization request/oauth/tokenAll parameters carried by, such as:/oauth/token? grant_type=phone_code&phone=xx&code=xx,phone,codeParameters are passed to the method.

The SMS verification code authorization mode is implemented

Create a custom authorization class called PhoneCodeGrantType that implements the ApiBootOauthTokenGranter interface, as shown below:

/** * Component Public class PhoneCodeGrantType ** @component Public class PhoneCodeGrantType Implements ApiBootOauthTokenGranter {/** * Authorization mode by mobile phone verification code */ private static final String GRANT_TYPE_PHONE_CODE = "phone_code"; /** * Authorization parameters: Mobile phone number */ private static final String PARAM_PHONE = "phone"; /** * Authentication parameters: Verification code */ private static final String PARAM_CODE = "code"; /** * Mobile phone verification code service logic */ @autoWired private PhoneCodeService PhoneCodeService; /** * @autowired private UserService UserService; @Override public String grantType() { return GRANT_TYPE_PHONE_CODE; } /** * Query user information based on user-defined authorization parameters ** @param parameters * @return * @throws ApiBootTokenException */ @override public UserDetails loadByParameter(Map<String, String> parameters) throws ApiBootTokenException { String phone = parameters.get(PARAM_PHONE); String code = parameters.get(PARAM_CODE); PhoneCode phoneCode = phoneCodeService.findPhoneCode(phone, code); If (objectutils.isEmpty (phoneCode)) {throw new ApiBootTokenException(" login failed, verification code: "+ code +", expired."); } UserDetails userDetails = userService.findByPhone(phone); If (objectutils.isEmpty (userDetails)) {throw new ApiBootTokenException(" user: "+ phone +", no existing."); } return userDetails; }}Copy the code

In the loadByParameter method, we first obtain the two parameters of the login phone number and verification code, and query whether there is a record of this verification code (PS: There is no verification code expiration time limit, please add this to your own business). After verification of the verification code is passed, query the user information corresponding to the phone number and return the user to the ApiBoot OAuth2 framework to complete verification.

If an exception occurs within the validation business logic method, it can be thrown directly using the ApiBootTokenException exception.

Run the test

To run our project, try to obtain AccessToken using CURL, as shown below:

➜ ~ curl -x POST hengboy: chapter @ localhost: 9090 / request/token - d 'grant_type = phone_code & phone = 17111111111 & code = 123123' {"access_token":"30e3f7d0-8c53-4dfe-b1ff-523a1db7b9eb","token_type":"bearer","refresh_token":"4b1f0ad5-f869-46ca-8b45-02 31e69316b3","expires_in":7194,"scope":"api"}Copy the code

Obtain AccessToken in postman mode, as shown below:

Type on the blackboard and underline

Based on the example of SMS verification code login, this chapter explains how to use ApiBoot OAuth2 to customize authorization methods to obtain AccessToken. The focus of this example is to customize GrantType and verify it according to various situations in production to ensure data security.

Code sample

If you like this article please click Star for source repository, thanks!! The sample source code for this article can be obtained from the apiboot-define-oauth-grant type directory:

  • Gitee:Gitee.com/minbox-proj…

Author’s Personal blog

Use the open source framework ApiBoot to help you become an Api service architect