SpringSecurity integration OAuth2 is the developer recognized resource protection, service certification of the best collocation partner, this good gay friends have been silently guarding the security of application services, according to the different role of visitors can be granular control to the specific interface, so as to achieve the fine division of permissions.
The SpringSecurity framework in the security framework team is relatively high entry level, although Spring through SpringBoot encapsulation, but there are still a lot of easy to miss configuration, because the configuration is more difficult for beginners to understand, To solve this problem, ApiBoot encapsulates SpringSecurity and OAuth2, greatly simplifying the configuration on the basis of which (only simplifying and enhancing, the basic syntax and configuration of SpringSecurity can still be used normally).
ApiBoot Security series
- ApiBoot implements zero code integration with Spring Security & OAuth2
- Zero code ApiBoot integrates Spring Security’s JDBC approach to AccessToken
Create a project
Create a SpringBoot project using the IDEA development tool.
The underlying layer of the ApiBoot is SpringBoot, and ApiBoot has created a 2.2.x branch version to support the 2.2.x branch of SpringBoot.
Add the ApiBoot unified dependency
After creating the project we need to add a unified version of the ApiBoot dependency to pom.xml as follows:
<dependencyManagement> <dependencies> <dependency> <groupId>org.minbox.framework</groupId> < artifactId > API - the boot - dependencies < / artifactId > < version > 2.2.0. RELEASE < / version > < type > pom < / type > < scope > import < / scope > </dependency> </dependencies> </dependencyManagement>Copy the code
Adding dependencies
In this chapter, we need to query the user information in the database for authentication, so we need to add database-related dependencies in POM.xml, as shown below:
<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>Copy the code
ApiBoot Mybatis Enhance is used in this chapter. For details, please visit the official ApiBoot Mybatis Enhance documentation
Configuring a Data Source
After adding database-related dependencies, add the following configuration information to the application.yml file:
Spring: application: name: apiboot-security-oauth-custom-certification # datasource: type: Com. Zaxxer. Hikari. HikariDataSource url: JDBC: mysql: / / 127.0.0.1:3306 / test? characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver server: port: 9090Copy the code
Configuration ApiBoot Security
ApiBoot Security uses the memory mode to read user information by default. In this chapter, we need to change the JDBC mode and disable the default reading of user information. (ApiBoot Security provides a default internal table structure, adding data after creating a table can directly use user information for authentication. See: ApiBoot Security usage documentation).
Add the following configuration to the application.yml configuration file:
# API: boot: security: # ApiBoot: security JDBC # disables the default read user mode enable-default-store-delegate: falseCopy the code
The default value of the api.boot.security. Enable-default-store-delegate configuration parameter is true, that is, the api_boot_user_info user information table in the corresponding database of the data source is automatically read. When set to false, we need to implement the ApiBootStoreDelegate interface to customize the user information for the query.
Configuration ApiBoot request
Api-boot-starter-security-oauth-jwt also integrates OAuth2 by default, and the default data storage mode is the same as Spring Security. The main purpose of this chapter is to query authentication user information. Instead of client information, we still use the default memory method, but modify the default configuration information of the client, and add the following configuration in the application.yml file:
Clients: - clientId: Hengboy clientSecret: chapter grantTypes: password,refresh_tokenCopy the code
In ApiBoot OAuth2 default Client configuration information, can view the org. Minbox. Framework. The API. The boot. Autoconfigure. Request. ApiBootOauthProperties. The Client source code for details.
User authentication
Now that the configuration is complete, let’s write the query user information and deliver the user information to the ApiBoot Security framework for authentication and AccessToken generation.
The persistence framework used in this chapter is ApiBoot MyBatis Enhance, which can be used in the official documentation.
Create user table
Create a system user information table named system_user in the database as follows:
CREATE TABLE 'system_user' (' su_id 'varchar(36) COLLATE UTf8MB4_general_ci NOT NULL COMMENT' iD ', 'su_login_name' varchar(30) COLLATE UTf8MB4_general_ci DEFAULT NULL COMMENT 'login ', 'su_nick_name' varchar(30) COLLATE UTf8MB4_general_ci DEFAULT NULL COMMENT ' 'su_password' varchar(200) COLLATE UTf8MB4_general_ci DEFAULT NULL COMMENT 'username ', 'su_create_time' TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create time ',' su_status' int(11) DEFAULT '1' COMMENT 'status ', 1: normal, 0: frozen, -1: ', PRIMARY KEY (' su_id ')) ENGINE=InnoDB DEFAULT CHARSET= UTf8MB4 COLLATE= UTf8MB4_general_ci COMMENT=' sysinfo ';Copy the code
After the system_user user table is created, we add a user data entry to the table as follows:
INSERT INTO 'system_user' VALUES ('9b69fd26-14db-11ea-b743-dcd28627348e','yuqiyu',' yuqiyu' In the yu ', '$2 a $10 $RbJGpi v3PwkjrYENzOzTuMxazuanX3Qa2hwI/f55cYsZhFT nX3. 08:13:22', '2019-12-02', 1);Copy the code
When we login, the user name corresponds to the su_login_name field, while the password corresponds to the su_password field. Yuqiyu’s password is initialized to 123456, and the password format must be the encrypted ciphertext of BCryptPasswordEncoder.
Creating user entities
For the system_user table we need to create an entity to be used by ApiBoot MyBatis Enhance. Create an entity named SystemUser as shown below:
/** * @author */ @data @table (name = "system_user") public class SystemUser implements UserDetails { / user Id * * * * / @ Id (generatorType = KeyGeneratorTypeEnum. UUID) @ Column (name = "su_id") private String userId. /** * login_name */ @column (name = "su_login_name") private String loginName; /** * nickName */ @column (name = "su_nick_name") private String nickName; /** * password */ @column (name = "su_password") private String password; /** * createTime */ @column (name = "su_create_time") private String createTime; /** * User status * 1: normal, 0: frozen, -1: deleted */ @column (name = "su_status") private Integer status; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Collections.EMPTY_LIST; } @Override public String getUsername() { return this.loginName; } @Override public String getPassword() { return this.password; } /** * UserDetails provides the method, whether the user is not expired * can be extended according to the fields in the user data table, @override public Boolean isAccountNonExpired() {return true; } /** * UserDetails provides a method to determine whether the user is unlocked * can be extended based on the fields in the user's data table, * * @return */ @override public Boolean isAccountNonLocked() {return true; } /** * The method provided by UserDetails, whether the credentials are not expired * can be extended according to the fields in the user's data table, * * @return */ @override public Boolean isCredentialsNonExpired() {return true; } /** * public Boolean isEnabled() {return this.status == 1; }}Copy the code
See the ApiBoot MyBatis Enhance documentation for more details on how to use these annotations. Another point to note here is that SystemUser implements the UserDetails interface, Those of you who have used Spring Security know that this is the user detail interface definition provided by Spring Security. If we customize the query user, we should let us customize the user entity (note: Implement this interface and implement all the methods provided in the UserDetails interface.
Create user data interfaces
The user’s entity has been created, we need a basic data interface to query the user according to the user’s login name in this chapter, create an interface named SystemUserEnhanceMapper as follows:
/** * Enhanced Mapper provided by ApiBoot Enhance is automatically scanned and registered to IOC ** @author Constant yu young * @see org.minbox.framework.api.boot.autoconfigure.enhance.ApiBootMyBatisEnhanceAutoConfiguration */ public interface SystemUserEnhanceMapper extends EnhanceMapper<SystemUser, Integer> {/** * query user information based on the user loginName ** @param loginName {@link SystemUser#getLoginName()} * @return {@link SystemUser} */ SystemUser findByLoginName(@Param("loginName") String loginName); }Copy the code
This interface inherits the EnhanceMapper interface and can be scanned automatically to create an instance of the proxy and added to IOC so that we can inject it directly elsewhere in the project.
Note: The findByXxx method is a method naming rule query provided by ApiBoot MyBatis Enhance. Multiple query criteria can be appended with And Or Or, And the corresponding SQL is automatically generated based on the method rules.
Implement the ApiBootStoreDelegate interface
ApiBoot Security provides an interface, ApiBootStoreDelegate, which is used to query the specific information of the login user. When AccessToken is obtained by grant_type=password&username= XXX, ApiBoot Security passes the username parameter value directly into the ApiBootStoreDelegate#loadUserByUsername method, This allows us to query the user based on username and return it to ApiBoot Security for subsequent authentication.
Let’s create a class named UserService and implement the ApiBootStoreDelegate interface as follows:
/** * @author */ @service public class UserService implements ApiBootStoreDelegate {/** * logger instance */ static Logger logger = LoggerFactory.getLogger(UserService.class); /** * @autoWired Private SystemUserEnhanceMapper mapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDetails userDetails = mapper.findByLoginName(username); If (ObjectUtils. IsEmpty (populated userDetails)) {throw new UsernameNotFoundException (" user: "+", does not exist. "+ username); } logger.info(" Login user info: {}", json.tojsonString (userDetails)); return userDetails; }}Copy the code
The return value of the loadUserByUsername method is the UserDetails interface type. We already implemented this interface with SystemUser earlier, so we can directly return the SystemUser instance.
Run the test
With all the code in place, start the project as XxxxApplication.
Test point: Get AccessToken
Client clientId, clientSecret, API. Boot.oauth. clients clientId, clientSecret, API.
➜ ~ curl hengboy: chapter @ localhost: 9090 / request/token - d 'grant_type = password&username = yuqiyu&password = 123456' {"access_token":"3beb1bee-9ca6-45e1-9fb8-5fc181670f63","token_type":"bearer","refresh_token":"d2243e18-8ab3-4842-a98f-eb d79da94e2e","expires_in":7199,"scope":"api"}Copy the code
Test point: Refresh AccessToken
Update AccessToken with CURL
➜ ~ curl hengboy: chapter @ localhost: 9090 / request/token - d 'grant_type=refresh_token&refresh_token=d2243e18-8ab3-4842-a98f-ebd79da94e2e' {"access_token":"e842c2ee-5672-49db-a530-329186f36492","token_type":"bearer","refresh_token":"d2243e18-8ab3-4842-a98f-eb d79da94e2e","expires_in":7199,"scope":"api"}Copy the code
In application. Yml, the OAuth2 client hengboy has authorized two grant_type by configuring grantTypes, namely password and refresh_token. If other methods are needed, they can be added in the configuration file accordingly.
Type on the blackboard and underline
ApiBoot integrates Spring Security and OAuth2 to read and define user information. We only need to pay attention to how to read user information. The previously ignorant code configuration can be replaced by configuration files. The main content of this chapter is the ApiBootStoreDelegate interface. ApiBoot provides more functions, which will be shared with you in the future.
Code sample
Wechat scan the following TWO-DIMENSIONAL code to follow “programmer Heng Yu teenager”, reply to “source code” to obtain the source code warehouse address.
This chapter source inspring-boot-chapter
The warehouse directory isSpringBoot2.x/apiboot-security-oauth-custom-certification-user
Author’s Personal blog
Use the open source framework ApiBoot to help you become an Api service architect