springboot快速整合satoken进行按钮级别控制

本文档详细介绍了如何在微服务中集成Sa-Token权限认证库,包括添加依赖、配置信息、登录逻辑、全局过滤器设置、自定义权限验证接口扩展、权限控制注解的使用以及异常处理。通过Sa-Token实现用户权限管理和认证,确保系统安全。
摘要由CSDN通过智能技术生成

官方文档:http://sa-token.dev33.cn/
因为代码这一块上手就是在微服务里面整活,所以先拿出一个子服务来进行说明,上述的官方文档也比较齐全,最重要的是中文,不懂的话就看官方文档。

添加依赖

 <!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
            <version>1.28.0</version>
        </dependency>

因为是单独的说明,就不需要添加satoken-redis相关依赖

配置文件

# token名称 (同时也是cookie名称)
sa-token.token-name=satoken
# token有效期,单位s 默认30, -1代表永不过期
sa-token.timeout=2592000
# 是否输出操作日志
sa-token.is-log=true
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
sa-token.activity-timeout=-1
# token风格
sa-token.token-style=simple-uuid
# 是否允许同一账号并发登录 (true时允许一起登录,false时新登录挤掉旧登录)
sa-token.is-concurrent=false
spring.profiles.active=dev

代码修改
其实这个一个已经写好登陆的子项目,所以就暂时不需要重新编写登陆逻辑,只需要在登陆成功后添加以下两行代码,必须将tokenInfo返回给前端:

 StpUtil.login(user.getId());
 SaTokenInfo tokenInfo=StpUtil.getTokenInfo();

然后就是添加sa-token的全局过滤器:

/**
 * Sa-Token 权限认证 配置类
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    // 注册 Sa-Token 全局过滤器
    @Bean
    public SaServletFilter getSaServletFilter() {
        return new SaServletFilter()
                .addInclude("/**")
                .addExclude("/favicon.ico","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**" ,"/doc.html/**","/error")
                .setAuth(obj -> {
                    // 校验 Id-Token 身份凭证     —— 以下两句代码可简化为:SaIdUtil.checkCurrentRequestToken();
                    String token = SaHolder.getRequest().getHeader(SaIdUtil.ID_TOKEN);
                    log.info("manage子服务当前的ID_TOKEN:{}",token);
                    SaIdUtil.checkToken(token);
                    //SaIdUtil.checkToken(StpUtil.getTokenValue());

                })
                .setError(e -> {
                    return SaResult.error("manage子服务当前的异常"+e.getMessage());
                })
                ;
    }
    // 注册Sa-Token的注解拦截器,打开注解式鉴权功能
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.info("sa-token拦截器");
        registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**")
                // 排除外部调用接口
                .excludePathPatterns("/**/outer/**")
                // 排除指定url 排除企业logo 获取的方法
                .excludePathPatterns("/**/login/**", "/**/logout/**", "/**/error/**",
                        "/**/register/**", "/**/verify/**", "/**/monitorLogin/**", "/**/enterprise/get", "/**/enterprise/getLogo","/**/getSAStoken/**")
                .excludePathPatterns("/doc.html")
                // 排除swagger相关
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");;
    }
}

添加自定义权限验证接口扩展:
其实项目用的最多的还是按钮的权限,所以第二个方法写不写都无所谓。每次等了成功后,第一次查询会将信息存在sasession里面(redis),注销后就是重新设置

/**
 * 自定义权限验证接口扩展
 */
@Component // 保证此类被SpringBoot扫描,完成sa-token的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    private final String KEY_PERMS = "key_perms";
    private final String KEY_ROLENAMES = "key_rolenames";
    @Autowired
    private SysRoleDao sysRoleDao;
    @Autowired
    private SysUrlDao sysUrlDao;

    /**
     * 返回一个账号所拥有的权限码集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginKey) {

        SaSession session = StpUtil.getSession();
        if (session.get(KEY_PERMS) != null) {
            List<String> perms = (List<String>) session.get(KEY_PERMS);
            log.info("session信息:{}", session.get(KEY_PERMS));
            return perms;
        }
        // 通过用户id来获取权限
        List<SysRole> roles = sysRoleDao.getRoleListByUser(loginId.toString());
        List<String> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toList());
        List<SysPermission> permissions = sysUrlDao.getUnionPermission(roleIds);
        List<String> perms = permissions.stream().map(SysPermission::getPerms).collect(Collectors.toList());
        session.set(KEY_PERMS, perms);
        return perms;
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginKey) {
        SaSession session = StpUtil.getSession();
        if (session.get(KEY_ROLENAMES) != null) {
            List<String> roleNames = (List<String>) session.get(KEY_ROLENAMES);
            log.info("session信息:{}", session.get(KEY_ROLENAMES));
            return roleNames;
        }


        List<SysRole> roles = sysRoleDao.getRoleListByUser(loginId.toString());
        List<String> roleNames = roles.stream().map(SysRole::getRoleName).collect(Collectors.toList());
        session.set(KEY_ROLENAMES, roleNames);
        return roleNames;
    }

}

数据库方面,在你们的权限表只需要添加perms字段,将每一个的权限码写在里面
部分数据库截图
接下来就是在每一个控制层添加注解来进行权限控制:

    @SaCheckPermission(value={"sys:dept:add","sysadmin"},mode = SaMode.OR)//只要包含"sys:dept:add","sysadmin"的任何一个,就可以进行部门新增,此处用"sysadmin"的原因是,超级管理员只需要这一个权限就可以了,没有必要将所有的权限都写出来
    @PostMapping(value = "save")
    public Response save(Department department) {
        StpUtil.checkLogin();
        System.out.println("该用户已经成功登录");
        进行service代码操作
        return 。。。
    }

最后就是异常处理:

@RestControllerAdvice
public class ExternalException {
    /**
     * SpringBoot获取当前环境代码,Spring获取当前环境代码
     */
    @Value("${spring.profiles.active}")
    private String profiles;

    /**
     * 判断是否是Ajax请求
     *
     * @param request
     * @return
     */
    public boolean isAjax(HttpServletRequest request) {
        return (request.getHeader("X-Requested-With") != null
                && "XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString()));
    }

    // 在当前类每个方法进入之前触发的操作
    @ModelAttribute
    public void get(HttpServletRequest request) throws IOException {

    }

    // 全局异常拦截(拦截项目中的所有异常)
    @ExceptionHandler
    public Response handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        if ("dev".equals(profiles)) {
            // 打印堆栈,以供调试
            e.printStackTrace();
        }
        // 不同异常返回不同状态码
        Response aj = null;
//       if (e instanceof NotLoginException) { // 如果是未登录异常
//           NotLoginException ee = (NotLoginException) e;
//            aj = Response.error(ee.getMessage());
//            if (ee.getLoginType().equals("member") && !isAjax(request)) {
//                response.sendRedirect("/member/login");
//            } else if (!isAjax(request)) {
//                response.sendRedirect("/system/adminlogin");
//            } else {
//               aj = Response.error("请登录");
//            }
//        } else if (e instanceof NotRoleException) { // 如果是角色异常
//            NotRoleException ee = (NotRoleException) e;
//            aj = Response.error("无此角色:" + ee.getRole());
//        } else

        if(e instanceof NotLoginException){
            NotLoginException notLoginException= (NotLoginException) e;
            aj= Response.error("认证异常:"+notLoginException.getMessage());
        } else if (e instanceof NotPermissionException) { // 如果是权限异常
            NotPermissionException notPermissionException = (NotPermissionException) e;
            aj = Response.error("无此权限:" + notPermissionException.getCode()+",请联系管理员");
        } else { // 普通异常, 输出:5000 + 异常信息
            aj = Response.error(e.getMessage());
        }
        // 返回给前端
        return aj;
    }
}

其他的就暂时没有了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值