1. 程式人生 > 其它 >sa-token 鑑權框架(springboot整合)

sa-token 鑑權框架(springboot整合)

一個輕量級java許可權認證框架,讓鑑權變得簡單、優雅(官方文件描述 哈哈)

一、pom依賴

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

二、yml檔案配置

# Sa-Token配置
sa-token:
  # token名稱 (同時也是cookie名稱)
  token
-name: satoken # token有效期,單位s 預設30天, -1代表永不過期 timeout: 2592000 # token臨時有效期 (指定時間內無操作就視為token過期) 單位: 秒 activity-timeout: -1 # 是否允許同一賬號併發登入 (為true時允許一起登入, 為false時新登入擠掉舊登入) is-concurrent: true # 在多人登入同一賬號時,是否共用一個token (為true時所有登入共用一個token, 為false時每次登入新建一個token) is-share: false # token風格 token
-style: simple-uuid # 是否輸出操作日誌 is-log: false # 是否列印sa-token標識 is-print: false

三、實現sa-token許可權、角色資訊注入

import cn.dev33.satoken.stp.StpInterface;
import com.subgame.dao.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; /** * @Author dly * @Description 實現satoken許可權、角色資訊注入 * @Date 2021/11/6 * @Param * @return **/ @Component public class StpInterfaceImpl implements StpInterface { @Autowired UserMapper userMapper; @Override public List<String> getPermissionList(Object loginId, String loginType) { List<String> list = new ArrayList<>(); list.add("user_get");return list; } @Override public List<String> getRoleList(Object loginId, String loginType) { String roles = userMapper.selectByPrimaryKey(Integer.valueOf(loginId.toString())).getRoles(); List<String> list = Arrays.asList(roles.split(",")); return list; }

四、註冊攔截器

import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 註冊攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 註冊Sa-Token的路由攔截器
        registry.addInterceptor(new SaRouteInterceptor(
                (req, res, handler)-> {
                    // 根據路由劃分模組,不同模組不同鑑權
                    SaRouter.match("/user/**", r -> StpUtil.checkPermission("user_get"));
                    SaRouter.match("/manager/**",r -> StpUtil.checkRole("ADMIN"));
                }))
                .addPathPatterns("/**")
                .excludePathPatterns("/manager/adminLogin");
    }
}

五、登入介面資訊識別(根據實際情況自己寫的實現類)

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.strategy.SaStrategy;
import com.subgame.base.RespResult;
import com.subgame.base.SubGameException;
import com.subgame.dao.UserMapper;
import com.subgame.model.User;
import com.subgame.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.UUID;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;


    @Override
    public RespResult adminLogin(User user, HttpServletResponse response) {
        User userinfo = userMapper.selectUserByLoginName(user.getLoginName());
        String saltPassword = SaSecureUtil.md5BySalt(user.getPassword(), User.salt);
        if(null == userinfo||!saltPassword.equals(userinfo.getPassword())){
            throw new SubGameException(SubGameException.LoginError,SubGameException.LoginError_Code);
        }
        StpUtil.login(userinfo.getId().toString());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        response.setHeader(tokenInfo.getTokenName(),tokenInfo.getTokenValue());
        RespResult result = new RespResult();
        result.setData(userinfo);
        return result;
    }
}

六、異常處理

全域性異常攔截(攔截專案中所有異常)

import cn.dev33.satoken.exception.DisableLoginException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.subgame.base.RespResult;
import com.subgame.base.SubGameException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@ControllerAdvice
public class GlobalException {
    // 全域性異常攔截(攔截專案中的所有異常)
    @ResponseBody
    @ExceptionHandler
    public RespResult handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        // 列印堆疊,以供除錯
        System.out.println("全域性異常---------------");
        e.printStackTrace();
        // 不同異常返回不同狀態碼
        RespResult result = new RespResult();
        if (e instanceof NotLoginException) {    // 如果是未登入異常
            NotLoginException ee = (NotLoginException) e;
            result.setMessage(ee.getMessage());
            result.setReturnCode("-1");
        }
        else if(e instanceof NotRoleException) {        // 如果是角色異常
            NotRoleException ee = (NotRoleException) e;
            result.setReturnCode("-2");
            result.setMessage(" "+ee.getMessage());
        }
        else if(e instanceof NotPermissionException) {    // 如果是許可權異常
            NotPermissionException ee = (NotPermissionException) e;
            result.setReturnCode("-3");
            result.setMessage("無此許可權"+ ee.getCode());
        }
        else if(e instanceof DisableLoginException) {    // 如果是被封禁異常
            DisableLoginException ee = (DisableLoginException) e;
            result.setReturnCode("-4");
            result.setMessage("賬號被封禁:" + ee.getDisableTime() + "秒後解封");
        }else if(e instanceof SubGameException){
            SubGameException ee = (SubGameException)e;
            result.setReturnCode(ee.getCode());
            result.setMessage(ee.getMessage());
        }
        else {    // 普通異常, 輸出:500 + 異常資訊
            result.setMessage(e.getMessage());
            result.setReturnCode("-999");
        }
        // 返回給前端
        return result;
    }
}

封裝返回物件資訊RespResult

import java.io.Serializable;


public class RespResult<T> implements Serializable {

    private static final long serialVersionUID = 5461950698245974856L;

    // 返回程式碼
    private String returnCode;

    // 返回程式碼描述
    private String message;

    // 返回資料
    private T data;

    public RespResult() {
        this.returnCode = "0";
        this.message = "操作成功";
    }

    public String getReturnCode() {
        return returnCode;
    }

    public void setReturnCode(String returnCode) {
        this.returnCode = returnCode;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "{" + "\"" + "returnCode" + "\"" + ":" + returnCode + ", " + "\"" + "data" + "\"" + ":" + data + "}";
    }
}
View Code

自定義異常類 SubGameException

import org.apache.ibatis.annotations.Case;

public class SubGameException extends RuntimeException{

    public static final String LoginError = "使用者名稱或密碼錯誤";
    public static final String LoginError_Code = "-5";
    public String code;


    public String getCode() {
        return code;
    }

    public SubGameException(String message,String code){
        super(message);
        this.code = code;
    }

    public SubGameException(String message, Throwable cause) {
        super(message, cause);
    }

    public SubGameException(Throwable cause) {
        super(cause);
    }

}
View Code

根據api搭建大概簡單的鑑權框架

更多詳細其他配置資訊見官網:https://sa-token.dev33.cn/