從零開始學YC-Framework之鑑權

2022-06-02 12:02:08

一、YC-Framework鑑權是基於哪一個開源框架做的?

YC-Framework鑑權主要基於Dromara開源社群組織下的Sa-Token。

1.什麼是Sa-Token?

Sa-Token是一個輕量級Java許可權認證框架,主要解決:登入認證、許可權認證、Session對談、單點登入、OAuth2.0、微服務閘道器鑑權等一系列許可權相關問題。

2.Sa-Token目前具有哪些功能?

  • 登入認證 —— 單端登入、多端登入、同端互斥登入、七天內免登入。
  • 許可權認證 —— 許可權認證、角色認證、對談二級認證。
  • Session對談 —— 全端共用Session、單端獨享Session、自定義Session。
  • 踢人下線 —— 根據賬號id踢人下線、根據Token值踢人下線。
  • 賬號封禁 —— 指定天數封禁、永久封禁、設定解封時間。
  • 持久層擴充套件 —— 可整合Redis、Memcached等專業快取中介軟體,重啟資料不丟失。
  • 分散式對談 —— 提供jwt整合、共用資料中心兩種分散式對談方案。
  • 微服務閘道器鑑權 —— 適配Gateway、ShenYu、Zuul等常見閘道器的路由攔截認證。
  • 單點登入 —— 內建三種單點登入模式:無論是否跨域、是否共用Redis,都可以搞定。
  • OAuth2.0認證 —— 基於RFC-6749標準編寫,OAuth2.0標準流程的授權認證,支援openid模式。
  • 二級認證 —— 在已登入的基礎上再次認證,保證安全性。
  • Basic認證 —— 一行程式碼接入 Http Basic 認證。
  • 獨立Redis —— 將許可權快取與業務快取分離。
  • 臨時Token驗證 —— 解決短時間的Token授權問題。
  • 模擬他人賬號 —— 實時操作任意使用者狀態資料。
  • 臨時身份切換 —— 將對談身份臨時切換為其它賬號。
  • 前後臺分離 —— APP、小程式等不支援Cookie的終端。
  • 同端互斥登入 —— 像QQ一樣手機電腦同時線上,但是兩個手機上互斥登入。
  • 多賬號認證體系 —— 比如一個商城專案的user表和admin表分開鑑權。
  • 花式token生成 —— 內建六種Token風格,還可:自定義Token生成策略、自定義Token字首。
  • 註解式鑑權 —— 優雅的將鑑權與業務程式碼分離。
  • 路由攔截式鑑權 —— 根據路由攔截鑑權,可適配restful模式。
  • 自動續簽 —— 提供兩種Token過期策略,靈活搭配使用,還可自動續簽。
  • 對談治理 —— 提供方便靈活的對談查詢介面。
  • 記住我模式 —— 適配[記住我]模式,重啟瀏覽器免驗證。
  • 密碼加密 —— 提供密碼加密模組,可快速MD5、SHA1、SHA256、AES、RSA加密。
  • 全域性偵聽器 —— 在使用者登陸、登出、被踢下線等關鍵性操作時進行一些AOP操作。
  • 開箱即用 —— 提供SpringMVC、WebFlux等常見web框架starter整合包,真正的開箱即用。

3.為什麼要選擇Sa-Token?

我在從單體架構到分散式微服務架構的思考這篇文章中所強調技術選型的八點如業務相關性、框架流行度、學習曲線、檔案豐富程度、社群支援、單元測試、可延伸性、許可證等。Sa-Token均滿足。

4.Sa-Token的相關資料有哪些?

Sa-Token官方檔案:
https://sa-token.dev33.cn/doc/

Sa-Token Github原始碼:
https://github.com/dromara/sa-token

Sa-Token Gitee原始碼:
https://gitee.com/dromara/sa-token

基本上結合自己的業務需求,整體過一遍Sa-Token官方檔案,就能學會如何使用Sa-Token。

開源不易,如果Sa-Token對你幫助,不妨點個star鼓勵一下對應的開源小夥伴們!!!

二、如何執行YC-Framework相關的鑑權服務?

主要步驟如下:

  • 1.啟動Nacos。
  • 2.啟動閘道器服務(yc-gateway)。
  • 3.啟動認證服務(yc-auth)。
  • 4.啟動後臺管理服務(yc-admin)。

啟動完畢以後,通過瀏覽器存取本地地址:
http://localhost:8080/doc.html

可以看到如下效果:
圖一

接下來點選認證管理會出現如下列表,找到登入介面,輸入對應的資訊,如下所示,就表示登入成功:
圖二

三、YC-Framework中的鑑權模組的核心程式碼包含哪些?

YC-Framework中的鑑權模組叫yc-common-security,屬於yc-common模組下的子模組。如圖所示:
圖三

其中核心類叫SaTokenConfigure.java,程式碼如下:

@Configuration
@Slf4j
public class SaTokenConfigure implements WebMvcConfigurer, StpInterface {

    @Autowired
    private UserApi userApi;

    /**
     * 註冊攔截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        // 註冊路由攔截器,自定義驗證規則
        registry.addInterceptor(new SaRouteInterceptor((request, response, handler) -> {
            //登入認證
            SaRouter.match("/**", () -> StpUtil.checkLogin());
            // 角色認證 -- 攔截以 admin 開頭的路由,必須具備 admin 角色或者 super-admin 角色才可以通過認證
            SaRouter.match("/company/**", () -> StpUtil.checkRoleOr("admin", "super-admin"));
            //許可權認證
            SaRouter.match("/company/**", () -> StpUtil.checkPermission("company"));
            SaRouter.match("/user/**", () -> StpUtil.checkPermission("admin"));
            SaRouter.match("/role/**", () -> StpUtil.checkPermission("admin"));

        })).addPathPatterns("/**").excludePathPatterns(
                "/auth/**", "/doc.html", "/webjars/**", "/swagger-resources", "/actuator/**");
    }

    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        log.info("loginId:" + loginId + "||" + loginType);
        List<String> permList = new ArrayList<>();
        UserIdReqDTO permReq = new UserIdReqDTO();
        permReq.setUserId(handleUserId(loginId.toString()));
        RespBody<List<String>> resultBody = userApi.getPerm(permReq);
        if (RespCode.SELECT_SUCCESS.getCode().equals(resultBody.getCode())) {
            permList = resultBody.getData();
        }
        return permList;
    }

    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        log.info("loginId:" + loginId + "||" + loginType);
        List<String> roleList = new ArrayList<>();
        UserIdReqDTO permReq = new UserIdReqDTO();
        permReq.setUserId(handleUserId(loginId.toString()));
        RespBody<List<String>> resultBody = userApi.getRole(permReq);
        if (RespCode.SELECT_SUCCESS.getCode().equals(resultBody.getCode())) {
            roleList = resultBody.getData();
        }
        return roleList;
    }

    /**
     * 處理使用者ID
     *
     * @param userId
     * @return
     */
    private String handleUserId(String userId) {
        return userId.substring(userId.lastIndexOf(ApplicationConst.DEFAULT_FLAG) + 1).replace(ApplicationConst.DEFAULT_FLAG, ApplicationConst.NULL_STR);
    }
}

該程式碼存放目錄為:
https://github.com/developers-youcong/yc-framework/tree/main/yc-common/yc-common-security

不難看出基於攔截器相關。之前寫過一篇叫Java Web之三大利器的文章,所謂Java Web 三大利器指的是攔截器、過濾器、監聽器等。其中攔截器與過濾器在許可權認證相關用的比較多。

之前還寫過關於重構某網API服務的文章可供讀者朋友參考,這篇文章是基於公司系統許可權重構的背景,在此我提供了兩種方法,一種是基於原生的攔截器,另外一方面是基於Sa-Token。

四、YC-Framework為何將許可權模組化?

一方面符合YC-Framework的架構思想之一模組化;另外一方面在於按需引入,哪一個微服務需要,只需引入對應的依賴即可。如下所示:

<dependency>
    <groupId>com.yc.framework</groupId>
    <artifactId>yc-common-security</artifactId>
</dependency>