看完這篇文章你還感覺SpringSecurity整合OAuth2自定義查詢用戶復雜嗎?

SpringSecurity整合OAuth2是開發(fā)者公認的資源保護服務認證的最佳搭配伙伴霹疫,這對好基友一直在默默的守護著應用服務的安全,根據訪問者的不同角色可以顆粒度控制到具體的接口综芥,從而實現權限的細微劃分丽蝎。

SpringSecurity框架在安全框架的隊伍中算是入門比較高的,雖然Spring通過SpringBoot進行了封裝膀藐,但是使用起來還是有很多容易遺漏的配置屠阻,因為配置比較多,讓初學者理解起來也比較困難额各,針對這個問題ApiBootSpringSecurity以及OAuth2進行了封裝国觉,在基礎上極大的簡化了配置(只做簡化、增強虾啦,SpringSecurity的基礎語法麻诀、配置還可以正常使用)

免費教程專題

恒宇少年在博客整理三套免費學習教程專題,由于文章偏多特意添加了閱讀指南傲醉,新文章以及之前的文章都會在專題內陸續(xù)填充针饥,希望可以幫助大家解惑更多知識點。

創(chuàng)建項目

使用IDEA開發(fā)工具創(chuàng)建一個SpringBoot項目需频。

ApiBoot的底層是SpringBoot,而且ApiBoot為了支持SpringBoot2.2.x分支筷凤,也對應的創(chuàng)建了2.2.x分支版本昭殉。

添加ApiBoot統(tǒng)一依賴

創(chuàng)建完項目后我們需要在pom.xml添加ApiBoot的統(tǒng)一版本依賴苞七,如下所示:

<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添加數據庫相關的依賴挪丢,如下所示:

<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使用文檔

配置數據源

添加數據庫相關的依賴后,在application.yml文件內添加如下配置信息:

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

ApiBoot Security默認采用的是內存方式(memory)讀取用戶信息嗡呼,我們本章需要修改為JDBC方式壁榕,并且禁用默認讀取用戶信息ApiBoot Security內部提供了默認的表結構,建表后添加數據即可直接使用用戶信息進行認證任内,詳見:ApiBoot Security使用文檔)撵渡。

application.yml配置文件中添加如下配置:

# 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接口來進行自定義查詢的用戶信息趋距。

配置ApiBoot OAuth

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

ApiBootOAuth2默認的客戶端配置信息,可以通過查看org.minbox.framework.api.boot.autoconfigure.oauth.ApiBootOauthProperties.Client源碼了解詳情孩擂。

用戶認證

配置已經完成狼渊,下面我們來編寫查詢用戶信息,將用戶信息交給ApiBoot Security框架進行認證肋殴、生成AccessToken等操作囤锉。

本章使用的持久化框架是ApiBoot MyBatis Enhance,具體的使用方法請查看官方文檔护锤。

創(chuàng)建用戶表

我們在數據庫內創(chuàng)建一張名為system_user的系統(tǒng)用戶信息表官地,表結構如下所示:

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 '創(chuàng)建時間',
  `su_status` int(11) DEFAULT '1' COMMENT '用戶狀態(tài),1:正常烙懦,0:凍結驱入,-1:已刪除',
  PRIMARY KEY (`su_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系統(tǒng)用戶信息表';

system_user用戶表創(chuàng)建完成后,我們往這張表內添加一條用戶數據氯析,如下所示:

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加密后的密文雪情。

創(chuàng)建用戶實體

針對system_user表我們需要來創(chuàng)建一個ApiBoot MyBatis Enhance使用的實體,創(chuàng)建一個名為SystemUser的實體如下所示:


/**
 * 系統(tǒng)用戶基本信息
 *
 * @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;
    /**
     * 創(chuàng)建時間
     */
    @Column(name = "su_create_time")
    private String createTime;
    /**
     * 用戶狀態(tài)
     * 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接口內提供的方法图仓。

創(chuàng)建用戶數據接口

用戶的實體已經創(chuàng)建完成罐盔,我們本章需要一個根據用戶的登錄名來查詢用戶基本的數據接口,創(chuàng)建一個名為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>接口救崔,可以自動被掃描到創(chuàng)建代理的實例后并且加入IOC惶看,這樣我們在項目其他的地方可以直接注入使用。

注意:findByXxx方法是ApiBoot MyBatis Enhance提供的方法命名規(guī)則查詢六孵,多個查詢條件可以使用And或者Or追加纬黎,會自動根據方法的規(guī)則生成對應的SQL

實現ApiBootStoreDelegate接口

ApiBoot Security提供了一個接口ApiBootStoreDelegate劫窒,這個接口主要是用來查詢登錄用戶的具體信息的作用本今,當我們通過grant_type=password&username=xxx的方式進行獲取AccessToken時,ApiBoot Security會直接把username的參數值傳遞給ApiBootStoreDelegate#loadUserByUsername的方法內主巍,這樣我們就可以根據username進行查詢用戶并返回給ApiBoot Security做后續(xù)的認證操作冠息。

我們來創(chuàng)建一個名為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

在獲取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"}

測試點:刷新AccessToken

復制上面獲取到的refresh_token的值進行刷新翎嫡,下面是刷新AccessTokenCURL方式:

? ~ 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欠动,分別是passwordrefresh_token惑申,如果需要別的方式可以在配置文件內對應添加具伍。

敲黑板铆遭,劃重點

ApiBoot整合Spring Security以及OAuth2后讀取自定義用戶信息,我們只需要關注具體怎么讀取用戶信息沿猜,之前那些懵懵懂懂的代碼配置都可以通過配置文件的方式代替,本章的主要內容是ApiBootStoreDelegate這個接口碗脊,ApiBoot所提供的功能還不止這些啼肩,會陸續(xù)分享給大家。

代碼示例

微信掃描下圖二維碼關注“程序員恒宇少年”后衙伶,回復“源碼”即可獲取源碼倉庫地址祈坠。

本章節(jié)源碼在spring-boot-chapter倉庫內目錄為SpringBoot2.x/apiboot-security-oauth-custom-certification-user

作者個人 博客
使用開源框架 ApiBoot 助你成為Api接口服務架構師

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矢劲,隨后出現的幾起案子赦拘,更是在濱河造成了極大的恐慌,老刑警劉巖芬沉,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躺同,死亡現場離奇詭異,居然都是意外死亡丸逸,警方通過查閱死者的電腦和手機蹋艺,發(fā)現死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黄刚,“玉大人捎谨,你說我怎么就攤上這事°疚” “怎么了涛救?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長业扒。 經常有香客問我检吆,道長,這世上最難降的妖魔是什么凶赁? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任咧栗,我火速辦了婚禮,結果婚禮上虱肄,老公的妹妹穿的比我還像新娘致板。我一直安慰自己,他們只是感情好咏窿,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布斟或。 她就那樣靜靜地躺著,像睡著了一般集嵌。 火紅的嫁衣襯著肌膚如雪萝挤。 梳的紋絲不亂的頭發(fā)上御毅,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音怜珍,去河邊找鬼端蛆。 笑死,一個胖子當著我的面吹牛酥泛,可吹牛的內容都是我干的今豆。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼柔袁,長吁一口氣:“原來是場噩夢啊……” “哼呆躲!你這毒婦竟也來了?” 一聲冷哼從身側響起捶索,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤插掂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后腥例,有當地人在樹林里發(fā)現了一具尸體辅甥,經...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年院崇,在試婚紗的時候發(fā)現自己被綠了肆氓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡底瓣,死狀恐怖谢揪,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情捐凭,我是刑警寧澤拨扶,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站茁肠,受9級特大地震影響患民,放射性物質發(fā)生泄漏。R本人自食惡果不足惜垦梆,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一匹颤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧托猩,春花似錦印蓖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春他宛,著一層夾襖步出監(jiān)牢的瞬間船侧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工厅各, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留镜撩,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓队塘,卻偏偏與公主長得像琐鲁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子人灼,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內容