Spring security integration OAuth2 is recognized by developers as the best matching partner for resource protection and service authentication. This pair of good friends have been quietly guarding the security of application services. According to the different roles of visitors, they can control the granularity to specific interfaces, so as to realize the fine division of permissions.
The Spring security framework is relatively high in the team of security framework. Although Spring is encapsulated by Spring boot, there are many configurations that are easy to be missed in use. Because of the large number of configurations, it is difficult for beginners to understand. To solve this problem, ApiBoot encapsulates Spring security and OAuth2, which greatly simplifies the process Configuration (only for simplification and enhancement, the basic syntax and configuration of Spring security can also be used normally)
ApiBoot Security Series
- ApiBoot realizes zero code integration spring Security & oauth2
- ApiBoot zero code integration Spring Security's JDBC way to obtain AccessToken
Create project
Use the IDEA development tool to create a SpringBoot project.
The underlying layer of ApiBoot is SpringBoot. In order to support the 2.2.x branch of SpringBoot, ApiBoot also creates the 2.2.x branch version.
Add ApiBoot unified dependency
After creating the project, we need to add the unified version dependency of ApiBoot in pom.xml, as follows:
<dependencyManagement> <dependencies> <dependency> <groupId>org.minbox.framework</groupId> <artifactId>api-boot-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Add dependency
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 follows:
<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>
In this chapter, ApiBoot Mybatis Enhance is used. For specific use, please visit the official document ApiBoot MyBatis Enhance use document
Configure data sources
After adding database related dependencies, add the following configuration information in the application.yml file:
spring: application: name: apiboot-security-oauth-custom-certification-user # Data source configuration 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: 9090
Configure ApiBoot Security
ApiBoot Security uses memory to read user information by default. In this chapter, we need to modify it to JDBC mode, and disable the default reading of user information (the default table structure is provided in ApiBoot Security, and the user information can be directly used for authentication after adding data after the table is built. For details: API boot security usage document).
Add the following configuration to the application.yml configuration file:
# ApiBoot configuration api: boot: security: # ApiBoot Security uses JDBC to read users away: jdbc # Disable the default read user mode enable-default-store-delegate: false
The default value of api.boot.security.enable-default-store-delegate configuration parameter is true, that is to say, it will automatically read the API boot user info user information table in the database corresponding to the data source. When we set it to false, we need to implement the API bootstoredelete interface to customize the user information for query.
Configure ApiBoot OAuth
The API boot starter security OAuth JWT dependency also integrates OAuth2 internally by default, and the default data storage mode is the same as Spring Security. The main purpose of this chapter is to query the authentication user information, not the client information, so we still use the default memory mode, but modify the default configuration information of the client , add the configuration in the application.yml file as follows:
# ApiBoot configuration api: boot: oauth: # List of clients for ApiBoot OAuth2 clients: - clientId: hengboy clientSecret: chapter grantTypes: password,refresh_token
For the default client configuration information of OAuth2 in API boot, you can check the source code of org.minbox.framework.api.boot.autoconfigure.oauth.ApiBootOauthProperties.Client for details.
User authentication
The configuration has been completed. Let's write and query the user information, and give the user information to the ApiBoot Security framework for authentication, access token generation and other operations.
The persistence framework used in this chapter is ApiBoot MyBatis Enhance. Please refer to Official documents.
Create user table
We create a system user information table named system "user in the database. The table structure is as follows:
CREATE TABLE `system_user` ( `su_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'User number', `su_login_name` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Login name', `su_nick_name` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Nickname?', `su_password` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'User password', `su_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time', `su_status` int(11) DEFAULT '1' COMMENT 'User status, 1: normal, 0: frozen,-1: Deleted', PRIMARY KEY (`su_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='System user information table';
After the system user table is created, we add a piece of user data to this table, as shown below:
INSERT INTO `system_user` VALUES ('9b69fd26-14db-11ea-b743-dcd28627348e','yuqiyu','Heng Yu junior - Yu Qi Yu','$2a$10$RbJGpi.v3PwkjrYENzOzTuMxazuanX3Qa2hwI/f55cYsZhFT/nX3.','2019-12-02 08:13:22',1);
When we log in, the user name corresponds to the Su login name field, and the password corresponds to the Su password field. The password of yuqiyu is initialized to 123456, and the format of the password must be BCryptPasswordEncoder encrypted ciphertext.
Create user entity
For the system user table, we need to create an entity used by apiboot mybatis strength, and create an entity named SystemUser as follows:
/** * Basic information of system user * * @author Heng Yu junior */ @Data @Table(name = "system_user") public class SystemUser implements UserDetails { /** * User number */ @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; /** * Creation time */ @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 Provided method, whether the user has not expired * It can be extended according to the fields in the user data table. For the sake of demonstration, it is configured as true * * @return */ @Override public boolean isAccountNonExpired() { return true; } /** * UserDetails Provided method, whether the user is not locked * It can be extended according to the fields in the user data table. For the sake of demonstration, it is configured as true * * @return */ @Override public boolean isAccountNonLocked() { return true; } /** * UserDetails Method provided, whether the voucher has not expired * It can be extended according to the fields in the user data table. For the sake of demonstration, it is configured as true * * @return */ @Override public boolean isCredentialsNonExpired() { return true; } /** * UserDetails Method provided, enable or not * * @return */ @Override public boolean isEnabled() { return this.status == 1; } }
Please refer to the apiboot mybatis strength document for the specific annotation usage. Here, we also need to note that SystemUser implements the UserDetails interface. If you have used Spring Security, you should know that this is the user details interface definition provided by Spring Security. If you want to query users, you should let us customize the user entity The user entity (SystemUser entity) implements this interface and all the methods provided in the UserDetails interface.
Create user data interface
The user's entity has been created. In this chapter, we need to query the user's basic data interface according to the user's login name. Create an interface named SystemUserEnhanceMapper as follows:
/** * ApiBoot Enhance Enhanced Mapper provided * Automatically scanned and registered to IOC * * @author Heng Yu junior * @see org.minbox.framework.api.boot.autoconfigure.enhance.ApiBootMyBatisEnhanceAutoConfiguration */ public interface SystemUserEnhanceMapper extends EnhanceMapper<SystemUser, Integer> { /** * Query user information according to user login name * * @param loginName {@link SystemUser#getLoginName()} * @return {@link SystemUser} */ SystemUser findByLoginName(@Param("loginName") String loginName); }
This interface inherits the enhancemapper < entity, ID > interface. It can be automatically scanned to the instance where the agent is created and added to IOC, so that we can inject it directly in other parts of the project.
Note: findByXxx method is a method naming rule query provided by ApiBoot MyBatis Enhance. Multiple query conditions can be appended with And Or, And the corresponding SQL will be generated automatically according to the rules of the method.
Implement API bootstoredelete interface
ApiBoot Security provides an interface, apibootstoredelete, which is mainly used to query the specific information of the logged in user. When we obtain the access token through grant ﹐ type = password & username = XXX, ApiBoot Security will directly pass the parameter value of username to the method of apibootstoredelete ﹐ loaduserbyusername, so that we can Query users according to username and return to ApiBoot Security for subsequent authentication.
Let's create a class named UserService and implement the apibootstoredelete interface, as follows:
/** * Custom read user information * * @author Heng Yu junior */ @Service public class UserService implements ApiBootStoreDelegate { /** * logger instance */ static Logger logger = LoggerFactory.getLogger(UserService.class); /** * User data interface */ @Autowired private SystemUserEnhanceMapper mapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDetails userDetails = mapper.findByLoginName(username); if (ObjectUtils.isEmpty(userDetails)) { throw new UsernameNotFoundException("User:" + username + ",Non-existent."); } logger.info("Login user information:{}", JSON.toJSONString(userDetails)); return userDetails; } }
The return value of the loadUserByUsername method is the UserDetails interface type. We have implemented SystemUser before, so we can directly use the SystemUser instance as the return value.
Operation test
The code is ready to start the project in the way of xxxapplication.
Test point: get AccessToken
Before obtaining the AccessToken, we need to confirm the clientId and clientSecret configuration contents of the client of api.boot.oauth.clients configured in the application.yml file. The following is the way of CURL:
➜ ~ curl hengboy:chapter@localhost:9090/oauth/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-ebd79da94e2e","expires_in":7199,"scope":"api"}
Test point: refresh AccessToken
Copy the value of the refresh_token obtained above to refresh. The following is the CURL method for refreshing the AccessToken:
➜ ~ curl hengboy:chapter@localhost:9090/oauth/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-ebd79da94e2e","expires_in":7199,"scope":"api"}
hengboy, the OAuth2 client, authorizes two grant types, password and refresh token, in application.yml by configuring grant types. If you need other ways, you can add them in the configuration file.
Knock on the blackboard
After ApiBoot integrates Spring Security and OAuth2 to read user-defined information, we only need to pay attention to how to read user information. Previously, those ignorant code configurations can be replaced by configuration files. The main content of this chapter is the interface of ApiBoot storedelete. The functions provided by ApiBoot are not only these, but will be shared with you in succession.
Code example
Wechat scan the following two-dimensional code to pay attention to "programmer Hengyu youth", reply to "source code" to get the source code warehouse address.
The source code of this chapter is SpringBoot2.x/apiboot-security-oauth-custom-certification-user in the spring boot chapter warehouse