一个基于SpringSecurity的动态权限控制快速

前言

在日常项目中,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]
复制代码

效果展示

  1. 正常登录

    image-20210717184952681

  2. 缺少参数登录

    image-20210717184817191

  3. 正常访问

    image-20210717185436851

  4. 无权限访问

    image-20210717185409737

  5. 未登录访问

    image-20210717185510985

  6. Token 错误访问

    image-20210717190159035

包说明

 ├─authentication 鉴权相关处理
 ├─authorization  认证相关处理
 ├─config         Security配置
 ├─constant       常量
 ├─filter         过滤器(登录入口、JWT 处理入口)
 ├─handle         认证、鉴权结果处理器
 ├─loginlogic     抽象登录逻辑
 │  └─base
 ├─model          实体
 └─utils          工具类
复制代码

总体流程

登录请求

image-20210717182828940

业务请求

image-20210717183837434

快速使用

  1. 引入依赖

此包未发布到中央仓库,请自行安装至本地仓库。

 <dependency>
     <groupId>pri.damai</groupId>
     <artifactId>fast-security</artifactId>
     <version>0.0.1-SNAPSHOT</version>
 </dependency>
复制代码
  1. 提供用户查询接口。

    也就是对接用户数据库。

 @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("无此用户"));
     }
 }
复制代码
  1. 实现登录逻辑

    有几种登录方式,就有几种实现类。注意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);
     }
 }
复制代码
  1. 实现 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地址

Fast-Security

Fast-Security-Test

对你有用的话,记得点个小星星⭐⭐⭐。