Easy-Security 基于SpringBoot 实现用户登录认证以及授权框架 旨在轻量配置简便等!
- 支持角色/权限字符串认证
- 支持JWT生成Token
- 支持MD5 AES 密码加密
- 缓存支持Session (默认) Redis
SpringBoot Version | Easy-Security Version |
---|---|
2.XX.XX | 1.4.0 - 2.X.X |
3.XX.XX | 3.4.0 - 3.X.X |
<dependency>
<groupId>io.github.links-code</groupId>
<artifactId>easy-security-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
Gradle引入
implementation group: 'io.github.links-code', name: 'easy-security-spring-boot-starter', version: '1.4.0'
easy:
security:
#放行的请求
ignore-paths: ['/login']
@RestController
public class TestController {
//注入 SecurityManage管理者(所有操作围绕这个bean进行的)
@Autowired
SecurityManage securityManage;
@PostMapping(value = "/register")
public String register(LoginForm form) {
/**
* 这里为了简便不调用业务方法
* 省略一些操作....
*/
//等待保持实体对象POJO
User user = new User();
//TODO 对于密码进行加密 (必须)
String encodedPasswd = securityManage.encodePasswd(user.getPassword());
user.setPassword(encodedPasswd);
//再往数据库进行保存
return "success";
}
}
- ! 提示:需要扩展存储用户信息 继承UserInfo即可,完后再load
@RestController
public class TestController {
@Autowired
SecurityManage securityManage;
@PostMapping(value = "/login")
public String login(LoginForm form){
/**
* 数据库操作查询出来用户信息封装到
* com.cloud.UserInfo 如果保存更多用户信息 继承UserInfo即可
* TODO 注意 UserInfo的userId必须有值
*/
UserInfo userInfo = new UserInfo();
//TODO 验证密码(必须)
boolean verified = securityManage.verifyPassword(form.getPasswd(), passwd);
if (!verified){
throw new RuntimeException("密码不正确!");
}
//封装权限信息 (基于权限字符串认证)
List<String> list = user.getRoles().stream().map(Role::getAuthStr).collect(Collectors.toList());
userInfo.getAuthStr().addAll(list);
//TODO 保存用户信息 生成Token 返回给前端 (必须)
return securityManage.load(userInfo);
}
}
@RestController
public class TestController {
@Autowired
SecurityManage securityManage;
@PostMapping(value = "/test")
//加上 Permission权限注解即可
@Permission(value = "admin-query")
public UserInfo test(){
return securityManage.getUserInfo();
}
}
@Autowired
public SecurityManage securityManage;
//获取用户信息
UserInfo userInfo = securityManage.getUserInfo();
- 详细配置请往下见Doc
关于权限设计可以分两类
1.基于权限字符串授权
- 用户表设计
user_id | username | password | create_time | |
---|---|---|---|---|
1 | 张三 | 202cb962ac59075b964b07152d234b70 | 123@163.com | 2024-03-12 |
2 | 李四 | 202cb962ac59075b964b07152d234b70 | 159@qq.com | 2024-04-01 |
- 角色表设计
role_id | role_name | auth_str | create |
---|---|---|---|
1 | 管理员 | admin-query,admin-delete,admin-insert | 2024-03-01 |
2 | 普通用户 | people-query | 2024-01-01 |
- 角色与用户关系表
role_user_id | role_id | user_id |
---|---|---|
1 | 1 | 1 |
2 | 2 | 1 |
用户1 即使管理员也是普通用户
数据库查询(逗号进行拆分)出来吧字符串设置到 UserInfo的authStr中 再需要授权的接口上加上 例如 查询接口(只有管理员才可以进行查询 )
@Permission(value = "admin-query")
2.基于角色授权
-
两张表同上
-
角色表设计
role_id | role_name | role_tag | create |
---|---|---|---|
1 | 管理员 | 1 | 2024-03-01 |
2 | 普通用户 | 2 | 2024-01-01 |
数据库查询(逗号进行拆分)出来吧字符串设置到 UserInfo的rolesTag中 再需要授权的接口上加上 例如 查询接口(只有管理员才可以进行查询 )
@Permission(roles = {RoleType.ADMIN},type = AuthEnum.ROLE)
- 可以定义角色类型 (不要使用枚举)
public class RoleType {
public static final int ADMIN = 1;
public static final int PERSON = 2;
}
@Autowired
public SecurityManage securityManage;
//获取用户信息
UserInfo userInfo = securityManage.getUserInfo();
1.引入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.配置文件设置redis
spring:
redis:
host: 127.0.0.1
port: 6379
database: 0
- 注入配置bean
@Configuration
public class Config {
@Bean(name = {"securityCache"})
RedisSecurityCache securityCache(RedisTemplate<String,String> redisTemplate,SecurityProperties securityProperties){
return new RedisSecurityCache(redisTemplate,securityProperties);
}
}
easy:
security:
# 是否开启登录认证
enableLogin: true
# 是否开启权限认证
enableAuth: true
# token在请求头中名字
tokenName: 'token'
# token 签名
tokenPrivateKey: 'awd#awd?&8*'
# 缓存用户信息前缀 默认 user-info- + 用户ID
userInfoPrefixToCache: 'user-info-'
# 放行请求(放行登录请求 以及 主页以/home开头的请求)
ignore-paths: ['/login','/home/**']
# token过期时间以及缓存时间 针对redis缓存生效 默认session 自行设置session失效即可
overTime: 7
# 提前几天进行用户信息的续期
perExtendTime: 3
# 登录拦截器优先级 值越大优先级越小
loginInterceptorOrder: 1
# 权限拦截器优先级
authAspectOrder: 2
@Bean(name = {"passwordHandle"})
AESPasswordHandle aesPasswordHandle(){
return new AESPasswordHandle();
}
- 在前后端分离系统你可以捕获该权限认证框架抛出异常并且进行处理
@RestControllerAdvice
public class ExceptionHandle {
//为了方面演示 定义内部类 正常自已新建类统一异常响应体
static class Resp<T>{
public Integer code;
public String msg;
public T data;
public Resp(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
//未登录异常
@ExceptionHandler(value = {UNLoginException.class})
public Resp<String> handleUnLogon(UNLoginException unLoginException){
return new Resp<>(400,"未登录,请先登录!");
}
@ExceptionHandler(value = {UNPermissionException.class})
public Resp<String> handleUnLogon(UNPermissionException unPermissionException){
return new Resp<>(400,"您暂无权限");
}
@ExceptionHandler(value = {UNVerifyTokenException.class})
public Resp<String> handleUnLogon(UNVerifyTokenException unVerifyTokenException){
return new Resp<>(400,"token验证未通过");
}
@ExceptionHandler(value = {UserInfoOverTimeException.class})
public Resp<String> handleUnLogon(UserInfoOverTimeException userInfoOverTimeException){
return new Resp<>(400,"用户信息过期,请重新登录!");
}
}
- Mvc 需要替换类注解 @ControllerAdvice 并且注入视图解析器进行异常后视图的跳转