一个基于 Spring Security 的动态权限控制快速使用包
前言
在日常项目中,Spring Security 的默认认证流程满足不了的需求。
但是,一般的项目对于认证、鉴权这块儿的需要又是十分类似的。
所以,我针对日常项目的认证鉴权需求,将 Spring Security 进行了一层包装。
项目地址、以及测试项目地址,都放在文尾了。
项目说明
本项目完全基于 Spring Security
,只针对日常开发项目中的认证、动态权限需求做一层封装。
干净纯洁,没有其他乱七八糟的功能。
可用于项目快速开发、Spring Security
框架学习。
另鉴于目前 JWT 用的最多,内置封装逻辑为,认证成功后生成 token 返回。
token 中包含 userId、roleIds。Token 内容示例:
{
alg: "HS256"
}.
{
roles: "10,1,5",
exp: 1626480624,
userId: "1"
}.
[signature]
效果展示
-
正常登录
-
缺少参数登录
-
正常访问
-
无权限访问
-
未登录访问
-
Token 错误访问
包说明
├─authentication 鉴权相关处理
├─authorization 认证相关处理
├─config Security配置
├─constant 常量
├─filter 过滤器(登录入口、JWT 处理入口)
├─handle 认证、鉴权结果处理器
├─loginlogic 抽象登录逻辑
│ └─base
├─model 实体
└─utils 工具类
总体流程
登录请求
业务请求
快速使用
- 引入依赖
此包未发布到中央仓库,请自行安装至本地仓库。
<dependency>
<groupId>pri.damai</groupId>
<artifactId>fast-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
-
提供用户查询接口。
也就是对接用户数据库。
@Component
public class UserServiceImpl{
static List<FastUserInfo> userList = new ArrayList<>();
// .....
public FastUserInfo loadUserByPhone(String phone) {
return userList.stream()
.filter(user -> user.getPhone().equals(phone))
.findAny()
.orElseThrow(() -> new AuthenticationServiceException("无此用户"));
}
}
-
实现登录逻辑
有几种登录方式,就有几种实现类。注意
getSupportLoginType()
返回值要区别开。
@Component
public class PhoneLogin extends AbstractLoginLogic {
@Resource
UserServiceImpl userService;
@Override
public String getSupportLoginType() {
return "phone";
}
@Override
public void checkParam(LoginData loginData) throws AuthenticationException {
String msg = null;
if (loginData.getPhone() == null) {
msg = "手机号不可为空";
}
if (loginData.getPhoneVerifyCode() == null) {
msg = msg + ", 短信验证码不可为空";
}
if (!Objects.equals(msg, null)) {
this.throwException(msg);
}
}
@Override
protected void login(LoginData loginData) throws AuthenticationException {
if (!"22".equals(loginData.getPhoneVerifyCode())) {
this.throwException("验证码错误");
}
// 具体登录逻辑
FastUserInfo fastUserInfo = this.getUserDetails(loginData);
}
@Override
public FastUserInfo getUserDetails(LoginData loginData) {
return userService.loadUserByPhone(loginData.getPhone());
}
private void throwException(String msg) {
throw new AuthenticationServiceException(msg);
}
}
-
实现
ResourceService
接口 。通过此接口,提供权限查询功能。也就是对接权限数据库。缓存不缓存就在于你自己的实现了。
@Component
public class MyResourceImpl implements ResourceService {
static HashMap<String, List<String>> roleMap = new HashMap<>();
// ......
@Override
public List<String> getRolesByUrl(String url) {
return roleMap.get(url);
}
}
其他扩展功能
可选 yml 配置
以下配置均有默认值,有指定要求时再配置即可。
fast-security:
not-login-urls: # 指定无需登录即可访问的接口
- /user
login-url: # 指定登录接口的url
expiration: # 指定 token 过期时间
jwt-secret: # 指定 Jwt 密匙
authentication-failed-code: # 指定登录失败错误码
unauthorized-code: # 指定未认证错误码
permission-denied-code: # 指定未授权错误码
no-roles-pass: # 未配置Url时,是否直接放行
登录成功处理器
在实际开发中,我们可能需要存储 token。可实现 LoginSuccessResultHandler
接口来自定义功能。
@Component
public class GGLoginSuccessResultHandler implements LoginSuccessResultHandler {
@Override
public Object handleResult(UserDetails userDetails, String token) {
// 保存 token or 其他操作
return null;
}
}
自定义登录失败处理器
@Component
public class GGLoginFailureResultHandler implements LoginFailureResultHandler {
@Override
public Object handleResult(AuthenticationException e) {
return null;
}
}
GIT地址
对你有用的话,记得点个小星星⭐⭐⭐。
转载自:https://juejin.cn/post/6986595187812204551