本项目采用权限认证框架sa-tokensa-token-solon-plugin

pom.xml

<!--        鉴权-->
<dependency>
<groupId>org.noear</groupId>
<artifactId>sa-token-solon-plugin</artifactId>
</dependency>

配置

# sa-token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: xrilang-api-token
# token有效期,单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: -1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
allow-concurrent-login: true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: true
# token风格
token-style: uuid
# 是否输出操作日志
is-log: false

app.yml配置sa-token

登录认证

登录成功

相关资料:登录认证 (sa-token.cc)

首先是登录,登录成功了,调用StpUtil.login()方法,保存用户ID

该方法会自动生成token、token有效期等信息,和用户ID一起保存在Cookie当中

大致就是如上图这样的一些信息。

登录认证相关接口

这些方法官方文档有介绍,写成接口方便查询和操作。比如退出登录、查询token信息等等。


// 查询登录状态,浏览器访问: http://localhost:9420/sign/isLogin
@Mapping("/isLogin")
public String isLogin() {
return "当前会话是否登录:" + StpUtil.isLogin();
} /**
* 获取登录用户的id
* @return String
*/
@Mapping("/loginId")
public String loginId() {
return StpUtil.getLoginIdAsString();
} /**
* 获取登录用户的token
* @return String
*/
@Mapping("/loginToken")
public String loginToken() {
return StpUtil.getTokenValue();
} /**
* 退出登录
* @return String
*/
@Mapping("/logout")
public String isLogout() {
;
StpUtil.logout();
return loginId()+"退出登录";
} @Mapping("/token_timeout")
public Long getTokenTimeout(String account) {
return StpUtil.getTokenTimeout();
} /**
* 获取当前会话的 token 信息参数
* return
*/
@Mapping("/tokenInfo")
public SaTokenInfo getTokenInfo() {
return StpUtil.getTokenInfo();
}

路由拦截

相关参考资料:路由拦截鉴权 (sa-token.cc)

sa-token-solon-plugin和sa-token的写法可能会有一点区别。

这里使用的是sa-token-solon-plugin

首先注解是@Configuration

package cc.mllt.xrilang.WebConfig;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.solon.integration.SaTokenInterceptor;
import cn.dev33.satoken.stp.StpUtil;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
import org.noear.solon.core.handle.FilterChain;
import org.smartboot.http.common.logging.Logger;
import org.smartboot.http.common.logging.LoggerFactory; @Configuration
public class AppFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(AppFilter.class); @Bean
public SaTokenInterceptor saTokenInterceptor() {
return new SaTokenInterceptor()
.addInclude("/**/**")
.addExclude("/favicon.ico")
.addExclude("/sign/**")
.setAuth(req -> {
SaRouter.match("/**", StpUtil::checkLogin)
.match("/user/**", r -> StpUtil.checkPermission("user"))
.match("/admin/**", r -> StpUtil.checkPermission("admin"));
})
.setError(e -> {
log.error("未登录的非法请求。"+e.getMessage());
return "未登录";
})
.setBeforeAuth(req -> {
SaHolder.getResponse()
.setServer("xrilang-api-server")
.setHeader("X-Frame-Options", "SAMEORIGIN")
.setHeader("X-XSS-Protection", "1; mode=block")
.setHeader("X-Content-Type-Options", "nosniff");
});
} @Override
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
long start = System.currentTimeMillis();
try {
chain.doFilter(ctx);
if (!ctx.getHandled()) {
ctx.status(404);
ctx.output("Resource not found.");
}
} catch (Throwable e) {
ctx.status(500);
ctx.output(e.getMessage());
// 错误已经被 `setError` 方法记录,这里不再重复记录
}
long timeTaken = System.currentTimeMillis() - start;
log.info("Request processed in {} ms", timeTaken);
}
}

关键的地方在于

    public SaTokenInterceptor saTokenInterceptor() {
return new SaTokenInterceptor()
.addInclude("/**/**")
.addExclude("/favicon.ico")
.addExclude("/sign/**")
.setAuth(req -> {
SaRouter.match("/**", StpUtil::checkLogin)
.match("/user/**", r -> StpUtil.checkPermission("user"))
.match("/admin/**", r -> StpUtil.checkPermission("admin"));
})
.setError(e -> {
log.error("未登录的非法请求。"+e.getMessage());
return "未登录";
})
.setBeforeAuth(req -> {
SaHolder.getResponse()
.setServer("xrilang-api-server")
.setHeader("X-Frame-Options", "SAMEORIGIN")
.setHeader("X-XSS-Protection", "1; mode=block")
.setHeader("X-Content-Type-Options", "nosniff");
});
}

这个方法无需被调用。

配置好放行哪些,不放行哪些,错误返回信息就行。

Session会话

相关资料:Session会话 (sa-token.cc)

具体使用方法以后再更新。

集成redis

参考资料:集成 Redis (sa-token.cc)

这里使用官方文档的第二种方式集成redis

所有pom.xml现在是

<!--        鉴权-->
<dependency>
<groupId>org.noear</groupId>
<artifactId>sa-token-solon-plugin</artifactId>
</dependency>
<!--鉴权-redis-序列化-->
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version> 1.38.0</version>
</dependency>
<!-- Jackson 的 JSR310 支持模块 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version> 2.17.2</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version> 2.11.1</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version> 3.21.3</version>
</dependency>

然后配置redis连接信息

集成 Redis 后,是我额外手动保存数据,还是框架自动保存?

框架自动保存。集成 Redis 只需要引入对应的 pom依赖 即可,框架所有上层 API 保持不变。

我是创建了一个RedisConfig.java文件,代码如下

package cc.mllt.xrilang.WebConfig;

import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.solon.dao.SaTokenDaoOfRedissonJackson;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.smartboot.http.common.logging.Logger;
import org.smartboot.http.common.logging.LoggerFactory; @Configuration
public class RedisConfig {
static Logger log = LoggerFactory.getLogger(RedisConfig.class); @Inject(value="${redis.host}", autoRefreshed = true)
private String host; @Inject(value="${redis.port}", autoRefreshed = true)
private int port; // @Inject(value="${redis.password}", autoRefreshed = true)
// private String password; @Bean
public RedissonClient redissonClient() {
try {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" + host + ":" + port)
.setDatabase(1); // 使用配置中的数据库索引
// .setPassword(password);
RedissonClient redisson = Redisson.create(config);
log.info("连接redis成功");
return redisson;
}catch (Exception e){
log.error("连接redis失败,请检查Redis配置信息并先启动redis", e);
return null;
}
} @Bean
public SaTokenDao saTokenDao(RedissonClient redissonClient) {
return new SaTokenDaoOfRedissonJackson(redissonClient);
}
}

[solon]Solon开发实战之权限认证的更多相关文章

  1. Django 中使用权限认证

    权限认证 权限概念 """ 在实际开发中,项目中都有后台运营站点,运营站点里面会存在多个管理员, 那么不同的管理员会具备不同的任务和能力,那么要实现这样的管理员功能,那么 ...

  2. Solon Web 开发,七、视图模板与Mvc注解

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  3. thinkphp5的Auth权限认证实战

    thinkphp5的Auth权限认证实战 一.总结 一句话总结:基于角色的权限管理(真正做一遍,就会发现很简单,不然一直都是半懂不懂的) 角色 权限 真正做一遍,就会发现很简单,不然一直都是半懂不懂的 ...

  4. Hangfire实战二——为DashBoard页面添加权限认证

    概述 Hangfire Dashboard为我们提供了可视化的对后台任务进行管理的界面,我们可以直接在这个页面上对定时任务进行删除.立即执行等操作,如下图所示: 默认情况下,这个页面只能在部署Hang ...

  5. Solon Web 开发

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  6. Solon Web 开发,一、开始

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  7. Solon Web 开发,二、开发知识准备

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  8. Solon Web 开发,四、请求上下文

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  9. Solon Web 开发,五、数据访问、事务与缓存应用

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  10. Solon Web 开发,六、过滤器、处理、拦截器

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

随机推荐

  1. 105份墨天轮“国产化迁移”干货文档汇总(含TiDB、openGauss、上云等)

    当前国产数据库产品百花齐放,随着政策的推进.技术的迭代以及市场需求的逐步扩大,数据库国产化正在加速进行中,有越来越多的金融.通信.制造.互联网等企业机构以及政府机关单位将业务系统从Oracle.MyS ...

  2. 统一携带 token

    tokne 可以使用 vuex 和 本地存储处理 : 一些接口需要携带token为了避免代码的重复性,可以在请求拦截器统一加入token ,每次请求都会携带token参数,不需要token参数的接口也 ...

  3. C#查漏补缺----Exception处理实现,无脑抛异常不可取

    前言 环境:.NET 8.0 系统:Windows11 参考资料:CLR via C#, .Net Core底层入门 https://andreabergia.com/blog/2023/05/err ...

  4. Android复习(三)清单文件中的元素——> provider、receiver、service

    <provider> 语法:   <provider android:authorities="list" android:directBootAware=[&q ...

  5. 神经网络之卷积篇:详解经典网络(Classic networks)

    详解经典网络 首先看看LeNet-5的网络结构,假设有一张32×32×1的图片,LeNet-5可以识别图中的手写数字,比如像这样手写数字7.LeNet-5是针对灰度图片训练的,所以图片的大小只有32× ...

  6. FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势

    ​喊了多年的互联网寒冬,今年的寒风格外凛冽,还在坚守安卓开发的朋友着实不容易.因为能转行的早就转了,能转岗的也早就转了,那么安卓程序员比较迷茫的就是,我该学什么安卓技术才好呢?还是直接扔了安卓再去搞别 ...

  7. 《你不知道的JavaScript》读书笔记(一):JS是如何查找变量的

    这本书之前囫囵地看了一遍,确实点明了很多以前不清不楚的点,但是仅仅看一遍是没什么用的,最近面试遇到不少原理相关的题感觉答得不理想,回头看下其实以前都理解过,但是没有记下来,正好结合实际的问题来再学习一 ...

  8. vue之计算属性computed模板

    计算属性:故名思意也是一种属性,可以用插值表达式直接调用 废话不多说,直接上代码: 页面部分 <!-- 用户名下拉菜单 --> <el-dropdown class="us ...

  9. esp8266+http (PlatformIO)

    esp8266 + http 使用esp8266发起http请求 #include <Arduino.h> #include <ESP8266WiFi.h> #include ...

  10. [解决方案] 几种通过 iproute2 来打通不同节点间容器网络的方式

    几种通过 iproute2 来打通不同节点间容器网络的方式 几种通过 iproute2 来打通不同节点间容器网络的方式 host-gw ipip vxlan 背景 之前由于需要打通不同节点间的容器网络 ...