当前位置:   article > 正文

sa-token 鉴权框架(springboot集成)

sa-token

一个轻量级java权限认证框架,让鉴权变得简单、优雅(官方文档描述 哈哈)

一、pom依赖

<dependency>
     <groupId>cn.dev33</groupId>
     <artifactId>sa-token-spring-boot-starter</artifactId>
     <version>1.27.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

二、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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

三、实现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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

四、注册拦截器

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");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

五、登录接口信息识别(根据实际情况自己写的实现类)

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

六、异常处理

全局异常拦截(拦截项目中所有异常)

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

封装返回对象信息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 + "}";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

自定义异常类 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);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

根据api搭建大概简单的鉴权框架

更多详细其他配置信息见官网:https://sa-token.dev33.cn/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/927280
推荐阅读
相关标签
  

闽ICP备14008679号