欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot 如何使用 SaToken 進行登錄認證、權(quán)限管理及路由規(guī)則接口攔截

 更新時間:2024年06月12日 10:11:57   作者:繁華盡頭滿是殤  
Sa-Token 是一個輕量級 Java 權(quán)限認證框架,主要解決:登錄認證、權(quán)限認證、單點登錄、OAuth2.0、分布式Session會話、微服務網(wǎng)關鑒權(quán) 等一系列權(quán)限相關問題,這篇文章主要介紹了Springboot 使用 SaToken 進行登錄認證、權(quán)限管理以及路由規(guī)則接口攔截,需要的朋友可以參考下

Springboot 使用 SaToken 進行登錄認證、權(quán)限管理以及路由規(guī)則接口攔截 

前言

Sa-Token 是一個輕量級 Java 權(quán)限認證框架,主要解決:登錄認證、權(quán)限認證、單點登錄、OAuth2.0、分布式Session會話、微服務網(wǎng)關鑒權(quán) 等一系列權(quán)限相關問題。
還有踢人下線、賬號封禁、路由攔截規(guī)則、微服務網(wǎng)關鑒權(quán)、密碼加密等豐富功能
它不比 Shiro 和 SpringSecurity 的功能少,而且配置使用更加簡單

一、引入和配置

先給你們看一下 Demo 文件結(jié)構(gòu)

在這里插入圖片描述

1.引入依賴

如果不需要將 token 信息存入 redis,只需要引入下面這一個依賴

<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.31.0</version>
</dependency>

如果需要將 token 存入 redis,則還需要引入下面的依賴(一般搭建單點登錄服務器才需要使用 redis)

使用redis ,無需任何其他配置,只需要多引入下面幾個依賴,然后下面的 yml 加一些配置,satoken 就可以自動存儲到 redis,非常方便

<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式)-->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-dao-redis-jackson</artifactId>
    <version>1.31.0</version>
</dependency>
<!-- Sa-Token插件:權(quán)限緩存與業(yè)務緩存分離 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-alone-redis</artifactId>
    <version>1.31.0</version>
</dependency>
<!-- 提供Redis連接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2、配置yml

如下代碼,如果不需要使用 redis ,則刪除 alone-redisspring redis配置,否則連接不到 redis 會報錯

如果使用了 redis,我下面的配置是業(yè)務和鑒權(quán)分離的方式,也就是說,token 存儲在 alone-redis 里面配置的數(shù)據(jù)庫,我這里配置的是 0 號數(shù)據(jù)庫,它和 spring reids 配置的數(shù)據(jù)庫不沖突

server:
  port: 8081
# Sa-Token配置
sa-token:
  # token前綴
  # Token前綴 與 Token值 之間必須有一個空格。
  # 一旦配置了 Token前綴,則前端提交 Token 時,必須帶有前綴,否則會導致框架無法讀取 Token。
  # 由于Cookie中無法存儲空格字符,也就意味配置 Token 前綴后,Cookie 鑒權(quán)方式將會失效,此時只能將 Token 提交到header里進行傳輸
  # token-prefix: Bearer
  # token 名稱 (同時也是cookie名稱)
  token-name: satoken
  # token 有效期,單位s 默認30天, -1代表永不過期
  timeout: 2592000
  # token 臨時有效期 (指定時間內(nèi)無操作就視為token過期) 單位: 秒
  activity-timeout: -1
  # 是否允許同一賬號并發(fā)登錄 (為true時允許一起登錄, 為false時新登錄擠掉舊登錄)
  is-concurrent: true
  # 在多人登錄同一賬號時,是否共用一個token (為true時所有登錄共用一個token, 為false時每次登錄新建一個token)
  is-share: false
  # token風格
  token-style: uuid
  # 是否輸出操作日志
  is-log: true
  # 配置 Sa-Token 單獨使用的 Redis 連接
  alone-redis:
    # Redis數(shù)據(jù)庫索引(默認為0)
    database: 0
    # Redis服務器地址
    host: 127.0.0.1
    # Redis服務器連接端口
    port: 6379
    # Redis服務器連接密碼(默認為空)
    password:
    # 連接超時時間
    timeout: 10s
spring:
  # 配置業(yè)務使用的 Redis 連接
  redis:
    # Redis數(shù)據(jù)庫索引(默認為0)
    database: 1
    # Redis服務器地址
    host: 127.0.0.1
    # Redis服務器連接端口
    port: 6379
    # Redis服務器連接密碼(默認為空)
    password:
    # 連接超時時間
    timeout: 10s

3、配置全局異常處理

這一步可以不配置,配置的作用是,在鑒權(quán)失敗的時候,不會報錯,而是返回給前端鑒權(quán)失敗的原因,方便我們開發(fā)調(diào)試

下面的異常會在鑒權(quán)失敗的時候自動返回到前端,無需我們手動拋出和返回

package pers.xuyijie.satokendemo.exception;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
 * @author 徐一杰
 * @date 2022/9/23 16:45
 * @description SaToken全局異常攔截
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 全局異常攔截,鑒權(quán)失敗不會報錯,會返回給前端報錯原因
      * @param e
     * @return
     */
    @ExceptionHandler
    public SaResult handlerException(Exception e) {
        e.printStackTrace();
        return SaResult.error(e.getMessage());
    }
}

4、模擬用戶角色和權(quán)限

這里我們給用戶分配一下我們模擬的角色和權(quán)限,正常你們要從數(shù)據(jù)庫讀取用戶的角色和擁有的權(quán)限

這里實現(xiàn)了 StpInterface 下面的方法,下面的方法會在接口鑒權(quán)之前自動調(diào)用,判斷角色和權(quán)限,無需我們手動調(diào)用

package pers.xuyijie.satokendemo.permission;
import cn.dev33.satoken.stp.StpInterface;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
 * @author 徐一杰
 * @date 2022/9/23 16:46
 * @description 獲取當前賬號的權(quán)限和角色列表,這個類下面的方法會在接口鑒權(quán)之前自動調(diào)用
 */
@Component
public class UserPermission implements StpInterface {
    /**
     * 返回一個賬號所擁有的權(quán)限碼集合
     * 即你在調(diào)用 StpUtil.login(id) 時寫入的標識值。
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 本list僅做模擬,實際項目中要根據(jù)具體業(yè)務邏輯來查詢權(quán)限
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("user-add");
        list.add("user-delete");
        list.add("user-update");
        list.add("user-get");
        list.add("article-get");
        System.out.println("用戶權(quán)限列表:" + list);
        return list;
    }
    /**
     * 返回一個賬號所擁有的角色標識集合 (權(quán)限與角色可分開校驗)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        // 本list僅做模擬,實際項目中要根據(jù)具體業(yè)務邏輯來查詢角色
        List<String> list = new ArrayList<>();
        list.add("user");
        list.add("admin");
        list.add("super-admin");
        System.out.println("用戶角色列表:" + list);
        return list;
    }
}

5、配置攔截器

如果在高版本 SpringBoot (≥2.6.x) 下注冊攔截器失效,則需要添加 @EnableWebMvc 注解才可以使用

下面我們配置的規(guī)則叫作路由攔截規(guī)則/user/** 意思就是接口地址為 /user 開頭的所有接口,也就是說,下面的我們 UserController 里面的所有接口都在攔截范圍內(nèi)

package pers.xuyijie.satokendemo.config;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
 * @author 徐一杰
 * @date 2022/9/23 16:49
 * @description
 */
@SpringBootConfiguration
@EnableWebMvc
public class SaTokenConfigure implements WebMvcConfigurer {
    /**
     * 注冊 Sa-Token 攔截器,打開注解式鑒權(quán)功能
     * 如果在高版本 SpringBoot (≥2.6.x) 下注冊攔截器失效,則需要額外添加 @EnableWebMvc 注解才可以使用
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注冊路由攔截器,自定義認證規(guī)則
        registry.addInterceptor(new SaInterceptor(handler -> {
            // 登錄認證 -- 攔截所有路由,并排除/user/doLogin 用于開放登錄
            SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
            // 角色認證 -- 攔截以 admin 開頭的路由,必須具備 admin 角色或者 super-admin 角色才可以通過認證
            SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
            // 權(quán)限認證 -- 不同模塊認證不同權(quán)限
            SaRouter.match("/user/**", r -> StpUtil.checkRole("user"));
            SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
            // 甚至你可以隨意的寫一個打印語句
            SaRouter.match("/**", r -> System.out.println("--------權(quán)限認證成功-------"));
        }).isAnnotation(true))
        //攔截所有接口
        .addPathPatterns("/**")
        //不攔截/user/doLogin登錄接口
        .excludePathPatterns("/user/doLogin");
    }
}

6、controller里調(diào)用satoken的方法

方法上面的注解是使用權(quán)限認證和攔截器的時候用的,下面我會講到

我在下面的UserController演示了登錄、注銷、檢查是否登錄、查看用戶token、獲取token有效期、對稱加密、非對稱加密方法,具體的方法每一行代碼的作用,都在注視中寫出來了,等一下我們測試每一個方法,為大家展示運行結(jié)果并解析代碼

package pers.xuyijie.satokendemo.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.basic.SaBasicUtil;
import cn.dev33.satoken.secure.SaBase64Util;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
 * @author 徐一杰
 * @date 2022/9/23 15:52
 * @description
 */
@RestController
@RequestMapping("/user")
public class UserController {
    private static final String USERNAME = "xyj";
    private static final String PASSWORD = "123456";
    /**
     * 測試登錄
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/doLogin")
    public SaResult  doLogin(String username, String password) {
        //這個方法會強制在瀏覽器彈出一個認證框
        SaBasicUtil.check("sa:123456");
        if(username.equals(USERNAME) && password.equals(PASSWORD)) {
            //這個是登錄用戶的主鍵,業(yè)務中你要從數(shù)據(jù)庫中讀取
            StpUtil.login(1);
            //獲取登錄生成的token
            tokenInfo = StpUtil.getTokenInfo();
            System.out.println(tokenInfo);
            return SaResult.ok("登錄成功,會話ID為 " + StpUtil.getLoginId() + " ,Token為:" + StpUtil.getTokenValue());
        }
        return SaResult.error("登錄失敗");
    }
    /**
     * 查詢登錄狀態(tài)
     * @return
     */
    @RequestMapping("/signOut")
    public SaResult signOut() {
        String loginId = null;
        if (StpUtil.isLogin()){
            loginId = (String) StpUtil.getLoginId();
            StpUtil.logout();
        }
        return SaResult.ok("會話ID為 " + loginId + " 的用戶注銷登錄成功");
    }
    /**
     * 查詢登錄狀態(tài)
     * @return
     */
    @RequestMapping("/isLogin")
    public SaResult isLogin() {
        if (StpUtil.isLogin()){
            return SaResult.ok("會話是否登錄:" + StpUtil.isLogin() + " ,會話ID為 " + StpUtil.getLoginId());
        }
        return SaResult.ok("會話是否登錄:" + StpUtil.isLogin());
    }
    /**
     * 根據(jù)Token值獲取對應的賬號id,如果未登錄,則返回 null
     * @param tokenValue
     * @return
     */
    @RequestMapping("/getUserByToken/{tokenValue}")
    public SaResult getUserByToken(@PathVariable String tokenValue){
        return SaResult.ok((String) StpUtil.getLoginIdByToken(tokenValue));
    }
    /**
     * 獲取當前會話剩余有效期(單位:s,返回-1代表永久有效)
     * @return
     */
    @RequestMapping("/getTokenTimeout")
    public SaResult getTokenTimeout(){
        return SaResult.ok(String.valueOf(StpUtil.getTokenTimeout()));
    }
    @SaIgnore
    @RequestMapping("/encodePassword")
    public void encodePassword() throws Exception {
        /**
         * md5加鹽加密: md5(md5(str) + md5(salt))
         */
        String md5 = SaSecureUtil.md5("123456");
        String md5BySalt = SaSecureUtil.md5BySalt("123456", "salt");
        System.out.println("MD5加密:" + md5);
        System.out.println("MD5加鹽加密:" + md5BySalt);
        /**
         * AES對稱加密
         */
        // 定義秘鑰和明文
        String key = "123456";
        String text = "這是一個明文用于測試AES對稱加密";
        // 加密
        String ciphertext = SaSecureUtil.aesEncrypt(key, text);
        System.out.println("AES加密后:" + ciphertext);
        // 解密
        String text2 = SaSecureUtil.aesDecrypt(key, ciphertext);
        System.out.println("AES解密后:" + text2);
        /**
         * RSA非對稱加密
         */
        // 定義私鑰和公鑰
        HashMap<String, String> keyMap = SaSecureUtil.rsaGenerateKeyPair();
        String privateKey = keyMap.get("private");
        String publicKey = keyMap.get("public");
        // 文本
        String text1 = "這是一個明文用于測試RSA非對稱加密";
        // 使用公鑰加密
        String ciphertext1 = SaSecureUtil.rsaEncryptByPublic(publicKey, text1);
        System.out.println("公鑰加密后:" + ciphertext1);
        // 使用私鑰解密
        String text3 = SaSecureUtil.rsaDecryptByPrivate(privateKey, ciphertext1);
        System.out.println("私鑰解密后:" + text3);
        /**
         * Base64
         */
        // 文本
        String text4 = "這是一個明文用于測試Base64";
        // 使用Base64編碼
        String base64Text = SaBase64Util.encode(text4);
        System.out.println("Base64編碼后:" + base64Text);
        // 使用Base64解碼
        String text5 = SaBase64Util.decode(base64Text);
        System.out.println("Base64解碼后:" + text5);
    }
}

下面的TestController里面等下演示權(quán)限認證和路由攔截的時候用

package pers.xuyijie.satokendemo.controller;
import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author 徐一杰
 * @date 2022/9/23 16:38
 * @description
 */
@RestController
@RequestMapping("/test")
@SaCheckLogin
public class TestController {
    /**
     * 此接口加上了 @SaIgnore 可以游客訪問
      * @return
     */
    @SaIgnore
    @RequestMapping("/getList")
    public SaResult getList() {
        return SaResult.ok("無需登錄接口");
    }
    /**
     * 登陸后才可調(diào)用該方法
     * @return
     */
    @SaCheckLogin
    @RequestMapping("/select")
    public SaResult select(){
        return SaResult.ok("查詢成功");
    }
    /**
     * 必須具有指定權(quán)限才能進入該方法
     * @return
     */
    @SaCheckRole("super-admin")
    @RequestMapping("/delete")
    public SaResult delete() {
        return SaResult.ok("刪除成功");
    }
    /**
     * 注解式鑒權(quán):SaMode.OR 只要具有其中一個權(quán)限即可通過校驗
     * @return
     */
    @RequestMapping("/add")
    @SaCheckPermission(value = {"user-add", "user-all"}, mode = SaMode.OR)
    public SaResult add() {
        return SaResult.ok("添加成功");
    }
    /**
     * 一個接口在具有權(quán)限 user-update 或角色 admin 時可以調(diào)通
     * @return
     */
    @RequestMapping("/update")
    @SaCheckPermission(value = "user-add", orRole = "admin")
    public SaResult update() {
        return SaResult.ok("更新成功");
    }
    /**
     * 這個接口測試用
     * @return
     */
    @RequestMapping("/testPermission")
    @SaCheckPermission(value = "user123")
    public SaResult testPermission() {
        return SaResult.ok("這個接口測試用");
    }
}

二、登錄演示

到這里,我么前期的配置就已經(jīng)結(jié)束了,下面我開始測試每一個方法,為大家展示運行結(jié)果并解析代碼,先把項目運行起來

在這里插入圖片描述

1、登錄-doLogin

大家請看,我在請求 /doLogin 這個接口的時候,彈出了下面的認證框,這個就是方法第一行代碼的功能,這叫 Basic認證,當然可以不要這一行代碼,隨你們,認證賬號 sa 密碼 123456

//這個方法會強制在瀏覽器彈出一個認證框
SaBasicUtil.check("sa:123456");

在這里插入圖片描述

進行 Basic認證 后,登陸成功

在這里插入圖片描述

我這里使用了 redis ,token 已經(jīng)存儲進來了

在這里插入圖片描述

2、驗證登錄-isLogin

在這里插入圖片描述

3、獲取token時效-getTokenTimeout

這是我們在 yml 里面配置的時效性,30天的毫秒

在這里插入圖片描述

4、加密

請求 encodePassword 接口

在這里插入圖片描述

5、注銷登錄-logout

在這里插入圖片描述

三、權(quán)限認證和攔截器演示

下面演示上面我們配置的攔截器,satoken 可以直接使用注解來進行攔截,很方便

我們可以發(fā)現(xiàn),我在兩個 controller 里面使用了 satoken 的幾個注解,注解可以用在方法上或類上
@SaIgnore 忽略該方法,不進行任何攔截和鑒權(quán)
@SaCheckLogin 登錄后才可以調(diào)用該接口
@SaCheckRole("super-admin") 登錄用戶必須要是"super-admin"角色才可調(diào)用
@SaCheckPermission(value = "del") 登錄用戶必須要有"del"權(quán)限才可調(diào)用

1、登錄認證

下面我們調(diào)用添加了 @SaCheckLogin 注解的方法

(1) 未登錄情況

在這里插入圖片描述

(2) 已登陸情況

可以看到調(diào)用成功,控制臺打印出我們上面攔截器配置的輸出信息

在這里插入圖片描述

在這里插入圖片描述

2、權(quán)限認證

登錄后,我們調(diào)用增加了 @SaCheckPermission(value = "del") 注解的方法,可以看到提示無此權(quán)限:del,因為前面我們模擬用戶權(quán)限時,沒有給用戶分配 del 權(quán)限

在這里插入圖片描述

我們再調(diào)用增加了 @SaCheckRole("super-admin") 注解的方法,可以看到成功

在這里插入圖片描述

總結(jié)

到此這篇關于Springboot 使用 SaToken 進行登錄認證、權(quán)限管理以及路由規(guī)則接口攔截的文章就介紹到這了,更多相關Springboot SaToken登錄認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論