SpringSecurity
整合OAuth2
是開發者公認的資源保護
、服務認證
的最佳搭配夥伴,這對好基友一直在默默的守護着應用服務的安全,根據訪問者的不一樣角色能夠顆粒度控制到具體的接口,從而實現權限的細微劃分。html
而SpringSecurity
框架在安全框架的隊伍中算是入門比較高的,雖然Spring
經過SpringBoot
進行了封裝,可是使用起來仍是有不少容易遺漏的配置,由於配置比較多,讓初學者理解起來也比較困難,針對這個問題ApiBoot
對SpringSecurity
以及OAuth2
進行了封裝,在基礎上極大的簡化了配置(只作簡化、加強,SpringSecurity
的基礎語法、配置還能夠正常使用)java
使用IDEA
開發工具建立一個SpringBoot
項目。mysql
ApiBoot
的底層是SpringBoot
,並且ApiBoot
爲了支持SpringBoot
的2.2.x
分支,也對應的建立了2.2.x
分支版本。
建立完項目後咱們須要在pom.xml
添加ApiBoot
的統一版本依賴,以下所示:程序員
<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>
本章咱們須要查詢數據庫內的用戶信息進行認證,因此須要在pom.xml
添加數據庫相關的依賴,以下所示:web
<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>
在本章使用到了ApiBoot Mybatis Enhance
,具體的使用請訪問官方文檔ApiBoot MyBatis Enhance使用文檔spring
添加數據庫相關的依賴後,在application.yml
文件內添加以下配置信息:sql
spring: application: name: apiboot-security-oauth-custom-certification-user # 數據源配置 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
ApiBoot Security
默認採用的是內存方式
(memory)讀取用戶信息,咱們本章須要修改成JDBC
方式,而且禁用默認讀取用戶信息
(ApiBoot Security
內部提供了默認的表結構,建表後添加數據便可直接使用用戶信息進行認證,詳見:ApiBoot Security使用文檔)。數據庫
在application.yml
配置文件中添加以下配置:json
# ApiBoot配置 api: boot: security: # ApiBoot Security 使用JDBC方式讀取用戶 away: jdbc # 禁用默認的讀取用戶方式 enable-default-store-delegate: false
api.boot.security.enable-default-store-delegate
配置參數默認值爲true
,也就是會自動讀取數據源對應數據庫內的api_boot_user_info
用戶信息表,當咱們設置爲false
後須要經過實現ApiBootStoreDelegate
接口來進行自定義查詢的用戶信息。segmentfault
api-boot-starter-security-oauth-jwt
這個依賴內部也默認集成了OAuth2
,並且默認的數據存儲方式與Spring Security
一致也是內存方式(memory
),咱們本章的主要目的是查詢認證用戶信息
,而不是客戶端信息
,因此咱們仍是採用默認的內存方式,不過修改下客戶端的默認配置信息,在application.yml
文件內添加配置以下所示:
# ApiBoot配置 api: boot: oauth: # ApiBoot OAuth2的客戶端列表 clients: - clientId: hengboy clientSecret: chapter grantTypes: password,refresh_token
在ApiBoot
中OAuth2
默認的客戶端配置信息,能夠經過查看org.minbox.framework.api.boot.autoconfigure.oauth.ApiBootOauthProperties.Client
源碼瞭解詳情。
配置已經完成,下面咱們來編寫查詢用戶信息,將用戶信息交給ApiBoot Security
框架進行認證
、生成AccessToken
等操做。
本章使用的持久化框架是ApiBoot MyBatis Enhance
,具體的使用方法請查看官方文檔。
咱們在數據庫內建立一張名爲system_user
的系統用戶信息表,表結構以下所示:
CREATE TABLE `system_user` ( `su_id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT '用戶編號', `su_login_name` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登陸名', `su_nick_name` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '暱稱', `su_password` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用戶密碼', `su_create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間', `su_status` int(11) DEFAULT '1' COMMENT '用戶狀態,1:正常,0:凍結,-1:已刪除', PRIMARY KEY (`su_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系統用戶信息表';
system_user
用戶表建立完成後,咱們往這張表內添加一條用戶數據,以下所示:
INSERT INTO `system_user` VALUES ('9b69fd26-14db-11ea-b743-dcd28627348e','yuqiyu','恆宇少年 - 於起宇','$2a$10$RbJGpi.v3PwkjrYENzOzTuMxazuanX3Qa2hwI/f55cYsZhFT/nX3.','2019-12-02 08:13:22',1);
咱們在登陸時用戶名對應su_login_name
字段,而密碼則是對應su_password
字段,yuqiyu
這個用戶的密碼初始化爲123456
,密碼的格式必須爲BCryptPasswordEncoder
加密後的密文。
針對system_user
表咱們須要來建立一個ApiBoot MyBatis Enhance
使用的實體,建立一個名爲SystemUser
的實體以下所示:
/** * 系統用戶基本信息 * * @author 恆宇少年 */ @Data @Table(name = "system_user") public class SystemUser implements UserDetails { /** * 用戶編號 */ @Id(generatorType = KeyGeneratorTypeEnum.UUID) @Column(name = "su_id") private String userId; /** * 登陸名 */ @Column(name = "su_login_name") private String loginName; /** * 暱稱 */ @Column(name = "su_nick_name") private String nickName; /** * 密碼 */ @Column(name = "su_password") private String password; /** * 建立時間 */ @Column(name = "su_create_time") private String createTime; /** * 用戶狀態 * 1:正常,0:已凍結,-1:已刪除 */ @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提供的方法,用戶是否未過時 * 可根據本身用戶數據表內的字段進行擴展,這裏爲了演示配置爲true * * @return */ @Override public boolean isAccountNonExpired() { return true; } /** * UserDetails提供的方法,用戶是否未鎖定 * 可根據本身用戶數據表內的字段進行擴展,這裏爲了演示配置爲true * * @return */ @Override public boolean isAccountNonLocked() { return true; } /** * UserDetails提供的方法,憑證是否未過時 * 可根據本身用戶數據表內的字段進行擴展,這裏爲了演示配置爲true * * @return */ @Override public boolean isCredentialsNonExpired() { return true; } /** * UserDetails提供的方法,是否啓用 * * @return */ @Override public boolean isEnabled() { return this.status == 1; } }
具體的註解使用詳見ApiBoot MyBatis Enhance
文檔,這裏還一點須要注意的是,SystemUser
實現了UserDetails
接口,若是使用過Spring Security
的同窗應該都知道這是Spring Security
提供的用戶詳情接口定義,咱們若是自定義查詢用戶
就應該讓咱們自定義的用戶實體
(注:這是的自定義用戶實體也就是SystemUser實體)實現這個接口並所有實現UserDetails
接口內提供的方法。
用戶的實體已經建立完成,咱們本章須要一個根據用戶的登陸名
來查詢用戶基本的數據接口,建立一個名爲SystemUserEnhanceMapper
的接口以下所示:
/** * ApiBoot Enhance提供的加強Mapper * 自動被掃描而且註冊到IOC * * @author 恆宇少年 * @see org.minbox.framework.api.boot.autoconfigure.enhance.ApiBootMyBatisEnhanceAutoConfiguration */ public interface SystemUserEnhanceMapper extends EnhanceMapper<SystemUser, Integer> { /** * 根據用戶登陸名查詢用戶信息 * * @param loginName {@link SystemUser#getLoginName()} * @return {@link SystemUser} */ SystemUser findByLoginName(@Param("loginName") String loginName); }
該接口繼承了EnhanceMapper<Entity,ID>
接口,能夠自動被掃描到建立代理的實例
後而且加入IOC
,這樣咱們在項目其餘的地方能夠直接注入使用。
注意:findByXxx
方法是ApiBoot MyBatis Enhance
提供的方法命名規則查詢,多個查詢條件可使用And
或者Or
追加,會自動根據方法的規則生成對應的SQL
。
ApiBoot Security
提供了一個接口ApiBootStoreDelegate
,這個接口主要是用來查詢登陸用戶的具體信息的做用,當咱們經過grant_type=password&username=xxx
的方式進行獲取AccessToken
時,ApiBoot Security
會直接把username
的參數值傳遞給ApiBootStoreDelegate#loadUserByUsername
的方法內,這樣咱們就能夠根據username
進行查詢用戶並返回給ApiBoot Security
作後續的認證操做。
咱們來建立一個名爲UserService
的類並實現ApiBootStoreDelegate
接口,以下所示:
/** * 自定義讀取用戶信息 * * @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(userDetails)) { throw new UsernameNotFoundException("用戶:" + username + ",不存在."); } logger.info("登陸用戶的信息:{}", JSON.toJSONString(userDetails)); return userDetails; } }
loadUserByUsername
方法的返回值是UserDetails
接口類型,在以前咱們已經將SystemUser
實現了該接口,因此咱們能夠直接將SystemUser
實例做爲返回值。
代碼一切就緒,經過XxxxApplication
的方式來啓動項目。
在獲取AccessToken
以前,咱們須要確認application.yml
文件內配置的api.boot.oauth.clients
的客戶端的clientId
、clientSecret
配置內容,下面是經過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"}
複製上面獲取到的refresh_token
的值進行刷新,下面是刷新AccessToken
的CURL
方式:
➜ ~ 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
這個OAuth2
客戶端在application.yml
中經過配置grantTypes
受權了兩種grant_type
,分別是password
、refresh_token
,若是須要別的方式能夠在配置文件內對應添加。
ApiBoot
整合Spring Security
以及OAuth2
後讀取自定義用戶信息,咱們只須要關注具體怎麼讀取用戶信息,以前那些懵懵懂懂的代碼配置均可以經過配置文件
的方式代替,本章的主要內容是ApiBootStoreDelegate
這個接口,ApiBoot
所提供的功能還不止這些,會陸續分享給你們。
微信掃描下圖二維碼關注「程序員恆宇少年」後,回覆「源碼」便可獲取源碼倉庫地址。
本章節源碼在spring-boot-chapter
倉庫內目錄爲SpringBoot2.x/apiboot-security-oauth-custom-certification-user
做者我的 博客
使用開源框架 ApiBoot 助你成爲Api接口服務架構師