aBin9999 发表于 2023-4-20 18:25

Jwt使用Aop方式自定义权限注解认证

本帖最后由 aBin9999 于 2023-4-20 19:52 编辑

使用Aop前置通知方式, 在控制层上使用指定切面注解, 并赋予注解参数为访问接口所需角色权限代码, 进行身份认证和权限校验

> Demo环境 JDK11, SpringBoot 2.2.2.RELEASE

### 相关依赖坐标
```
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'io.jsonwebtoken:jjwt:0.9.0'
```

### 1、自定义权限认证注解
``` java
import java.lang.annotation.*;

/**
* 角色权限校验注解
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HasRoles {
    String[] roles() default "";
}
```

### 2、Aop前置通知切面类
```java
import com.example.dynamicdatatable.domain.SysAccountInfo;
import com.example.dynamicdatatable.enums.AccountType;
import com.example.dynamicdatatable.repository.SysAccountMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Set;

/**
* 权限认证切面类
*/
@Aspect
@Slf4j
@Component
public class CheckRoleAop {

    @Pointcut(value = "@annotation(HasRoles)")
    public void pointCut() {};
    @Resource
    private SysAccountMapper accountMapper;
    @Resource
    private HttpServletRequest request;

    /**
   * todo 身份认证和权限比对
   * @param hasRoles权限认证注解入参
   */
    @Before(value = "pointCut()&&@annotation(hasRoles)")
    public void exec(HasRoles hasRoles) {
      // jwt解密认证
      // ...
      // jwt解密认证结束
      long id = 10; // 模拟解析Token后 取得的id值
      AccountType accountType = AccountType.ADMIN_TYPE;   // 模拟解析Token后, 取得的用户账户类别
      // 每次请求都动态实时的去查询用户信息和权限信息
      SysAccountInfo accountInfo = accountMapper.findById(id, accountType);
      if (ObjectUtils.isEmpty(accountInfo) || !accountInfo.isEnableState() || accountInfo.isDelState()) {
            log.error("用户不存在");
            throw new RuntimeException("用户不存在");
      } else {
            // 模拟从数据库中查询账户拥有的角色身份权限
            Set<String> rolesToken = new HashSet<String>(1) {
                private static final long serialVersionUID = -1307833886578391108L;
                {
                  add("admin");
                }
            };
            String[] roles = hasRoles.roles();
            if (roles.length == 0) {
                return;
            } else {
                for (String role : roles) {
                  if (rolesToken.contains(role)) {
                        // 将解析后的Token信息实体缓存到请求域中
                        JwtSessionCacheEntity jwtSessionCacheEntity = new JwtSessionCacheEntity();
                        jwtSessionCacheEntity.setId(id);
                        jwtSessionCacheEntity.setAccountType(accountType);
                        jwtSessionCacheEntity.setRoleCode("admin");
                        request.setAttribute("info", jwtSessionCacheEntity);
                        return;
                  }
                }
            }
            log.warn("用户无对应的权限");
            throw new RuntimeException("无权限");
      }
    }

}
```

### 3、请求域缓存实体类
``` java
import lombok.Data;

import java.io.Serializable;

/**
* Jwt 请求域缓存数据实体
*/
@Data
public class JwtSessionCacheEntity implements Serializable {

    private static final long serialVersionUID = -4634413454684601681L;

    private Long id;
    private String roleCode;
    private AccountType accountType;

}
```

### 4、账户类型枚举类
``` java
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* 账户类型枚举类
*/
@Getter
@AllArgsConstructor
public enum AccountType {

    ACCOUNT_TYPE(1, "sys_account_info"),
    ADMIN_TYPE(2, "sys_admin_info"),

    ;

    private int code;
    private String tableName;

}
```

侃遍天下无二人 发表于 2023-4-20 19:37

稍微再重新编辑下,有些代码粘进来出问题了,记得禁用链接识别

aBin9999 发表于 2023-4-20 19:50

侃遍天下无二人 发表于 2023-4-20 19:37
稍微再重新编辑下,有些代码粘进来出问题了,记得禁用链接识别

okokok,感谢指点:lol

nwl909690050 发表于 2023-4-21 09:50

不错,就喜欢注解校验权限的。以前用过自定义注解,没基于jwt。顶

你猜啊 发表于 2023-4-21 10:54

aop就没必要了都到达了controller层了这个时候就没必要发生校验了。尽量在HandlerInterceptorAdapter去处理这些数据
页: [1]
查看完整版本: Jwt使用Aop方式自定义权限注解认证