前言
在日常项目中,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地址
对你有用的话,记得点个小星星⭐⭐⭐。