哈喽,大家好,我是指北君
。
大家有没有发现,现在我们已经习惯了一处登录,处处使用的设计,但是你知道该如何实现吗?又该如何优雅的实现?
前言
不知道在前几年互联网还没有那么发达的时候,大家有没有感触到?
那个时候我们还是不太敢把我们的钱都存放在支付宝里面,心里想着“看不见,摸不着”,很容易就会被盗取。而且那个时间段里面,一些黑客的入侵也比较频繁,在一些安全技术没有那么完善的前提下,确实也出现过几次鲜为人知的圈内大事件。
但是近三年的互联网飞速发展,我们好像已经习惯了享受:“一键登录支付宝,就可以在各大购物网站中畅快支付,不需要再进行频繁地登录与登出,只需要一个支付宝用户名和密码,就可以完成你想要做的所有事情”
大家有没有想过背后的原理呢? 可能对于我们程序员圈之外的人来说,这些好像会说:“这些不都该是基础的功能吗?”但是对于我们圈内的人来说,其中的原理与实现确实能够作为衡量我们技术水平的一个关键点。
但是我们该如何设计
首先让我们来看看【周志明-《深入理解java虚拟机》作者】在其凤凰架构
中写到的 架构安全性的几大要素:
- [认证](Authentication):系统如何正确分辨出操作用户的真实身份?
- [授权]( Authorization):系统如何控制一个用户该看到哪些数据、能操作哪些功能?
- [凭证](Credential):系统如何保证它与用户之间的承诺是双方当时真实意图的体现,是准确、完整且不可抵赖的?
- [保密](Confidentiality):系统如何保证敏感数据无法被包括系统管理员在内的内外部人员所窃取、滥用?
- [传输]:系统如何保证通过网络传输的信息无法被第三方窃听、篡改和冒充?
- [验证]:系统如何确保提交到每项服务中的数据是合乎规则的,不会对系统稳定性、数据一致性、正确性产生风险?
如上所示,首当其冲的就是认证——如何辨别是你,然后就是授权——如何访问数据,以及凭证——如何保证唯一性等等,在我们想要设计时候,也就可以从这些地方入手。无论是说引用已经存在的框架,或者是说自己去设计。
当然对于一些已经有着丰富经验的老司机可能会说:“shiro 和 SpringSecurity 不是都已经实现了这些功能吗,直接引入就好了,指北君又在卖什么关子呢,想要表达什么呢?”
这个时候指北君会很严肃的反驳大家,shiro
和 SpringSecurity
有对应的自定义 Realm
去进行权限的校验,需要设置对应的诸多全局过滤器,以及各种配置文件等等。
揭开面纱
而今天介绍的Sa-Token
是一个轻量级 Java 权限认证框架,主要解决:登录认证
、权限认证
、Session会话
、单点登录
、OAuth2.0
、微服务网关鉴权
等一系列权限相关问题。
对于登录来说 Sa-Token
只需要这样:
// 在登录时写入当前会话的账号id
StpUtil.login(10001);
// 然后在需要校验登录处调用以下方法:
// 如果当前会话未登录,这句代码会抛出 `NotLoginException` 异常
StpUtil.checkLogin();
至此,我们已经借助 Sa-Token
完成登录认证!
没错,在 Sa-Token
中,登录认证就是如此简单,不需要任何的复杂前置工作,只需这一行简单的API调用,就可以完成会话登录认证!
当你受够 Shiro
、SpringSecurity
等框架的三拜九叩之后,你就会明白,相对于这些传统老牌框架,Sa-Token
的 API 设计是多么的简单、优雅!
权限认证示例(只有具备 user:add
权限的会话才可以进入请求):
@SaCheckPermission("user:add")
@RequestMapping("/user/insert")
public String insert(SysUser user) {
// ...
return "用户增加";
}
将某个账号踢下线(待到对方再次访问系统时会抛出NotLoginException
异常):
// 将账号id为 10001 的会话踢下线
StpUtil.kickout(10001);
在 Sa-Token
中,绝大多数功能都可以 一行代码 完成:
StpUtil.login(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
StpUtil.logout(); // 当前会话注销登录
StpUtil.kickout(10001); // 将账号为10001的会话踢下线
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
StpUtil.getSession(); // 获取当前账号id的Session
StpUtil.getSessionByLoginId(