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:
When obtaining a verification code, the system saves the verification code in the database
When a user enters a verification code and submits a login request, the user reads the verification code and checks its validity
Finally, the user information corresponding to the mobile phone number is obtained to complete the login logic.
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 tellOAuth2
The custom ofGrantType
What it is depends on your business logic.loadByParameter
: This method is customGrantType
Business implementation of,parameters
Parameter contains the custom authorization request/oauth/token
All parameters carried by, such as:/oauth/token? grant_type=phone_code&phone=xx&code=xx
,phone
,code
Parameters 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