自定义鉴权注解与AOP

1.给上游业务方发放key和秘钥才能访问系统
2.上游根据DigestUtils.md5Hex(key.concat(时间戳).concat(秘钥).toUpperCase())生成token
3.传递给下游key,token,timespan
4.下游根据key查找数据库,用key和数据库的秘钥,时间戳重新进行加密
5.下游加密后的结果与上游传的token进行比较

上游传递参数:

@Data
public class AuthenticateBO {

    /**
     * 请求key
     */
    private String appKey;

    /**
     * 验证加密值 Md5(AppKey+Timespan+SecretKey) 加密的32位大写字符串)
     */
    private String token;

    /**
     * 精确到秒的Unix时间戳
     */
    private String timespan;

    /**
     * 服务code
     */
    private String serviceCode;

}

自定义注解:

/**
 * 鉴权注解
 *
 */
@Target(ElementType.METHOD)   // 注解范围,注解使用在方法上
@Retention(RetentionPolicy.RUNTIME)  // 生效时间
@Documented
public @interface Authenticate {

    /**
     * 服务code
     */
    String code();

}

AOP切面实现:

/**
 * 鉴权切面
 *
 */
@Slf4j
@Aspect
@Component
public class AuthenticateAspect extends BaseServiceImpl {

    @Pointcut("@annotation(com.xxx.service.paidplatform.annotation.Authenticate)")
    public void authenticate() {
    }
	
	// 环绕切入,@Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务
    @Around("authenticate()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取Authenticate注解的服务code
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        Authenticate authenticate = method.getAnnotation(Authenticate.class);
        String code = authenticate.code();

        // 参数值数组
        Object[] args = joinPoint.getArgs();
        AuthenticateBO basePageReqDTO = ObjectHelper.copy(args[0], AuthenticateBO.class);
        basePageReqDTO.setServiceCode(code);
        authenticate(basePageReqDTO);

        return joinPoint.proceed();
    }

    /**
     * 鉴权接口
     *
     * @since 2020/9/1
     */
    protected void authenticate(AuthenticateBO basePageReqDTO) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        ApplicationDO applicationDO = null;
        ServiceModuleDO serviceModuleDO = null;

        try {
            String serviceCode = basePageReqDTO.getServiceCode();
            Optional.ofNullable(serviceCode)
                    .orElseThrow(() -> new ServiceException(CustomErrorCodeEnum.SERVICE_CODE_NULLABLE.getValue(), CustomErrorCodeEnum.SERVICE_CODE_NULLABLE.getDescription()));
            //获取application_id
            Map<String, Object> sqlParams = Maps.newHashMap();
            sqlParams.put("isEnable", CommonBooleanEnum.TRUE.getValue());
            sqlParams.put("appKey", basePageReqDTO.getAppKey());
            applicationDO = dao.queryEntity(ApplicationDO.class, "application.get", sqlParams);
            Optional.ofNullable(applicationDO)
                    .orElseThrow(() -> new ServiceException(CustomErrorCodeEnum.APPLICATION_UN_FIND.getValue(), CustomErrorCodeEnum.APPLICATION_UN_FIND.getDescription()));

            //校验appKey和token
            String encryptKey = DigestUtils.md5Hex(applicationDO.getAppKey().concat(basePageReqDTO.getTimespan()).concat(applicationDO.getAppSecret()).toUpperCase());
            if (!Objects.equals(encryptKey, basePageReqDTO.getToken())) {
                throw new ServiceException(CustomErrorCodeEnum.INVALID_APP_KEY.getValue(), CustomErrorCodeEnum.INVALID_APP_KEY.getDescription());
            }

            //获取订阅的服务
            sqlParams.clear();
            sqlParams.put("applicationId", applicationDO.getId());
            List<ServiceSubscribeDO> serviceSubscribeList = dao.queryEntities(ServiceSubscribeDO.class, "serviceSubscribe.list", sqlParams);
            if (CollectionUtils.isEmpty(serviceSubscribeList)) {
                throw new ServiceException(CustomErrorCodeEnum.SERVICE_UNSUBSCRIBE.getValue(), CustomErrorCodeEnum.SERVICE_UNSUBSCRIBE.getDescription());
            }
            List<Long> serviceModuleIds = serviceSubscribeList.stream()
                    .map(ServiceSubscribeDO::getServiceModuleId)
                    .collect(Collectors.toList());

            //获取服务code
            sqlParams.clear();
            sqlParams.put("ids", serviceModuleIds);
            serviceModuleDO = dao.queryEntities(ServiceModuleDO.class, "serviceModule.list", sqlParams)
                    .stream().filter(i -> Objects.equals(i.getServiceModuleCode(), serviceCode)).findFirst().orElse(null);

            //鉴权
            if (Objects.isNull(serviceModuleDO)) {
                throw new ServiceException(CustomErrorCodeEnum.SERVICE_UNSUBSCRIBE.getValue(), CustomErrorCodeEnum.SERVICE_UNSUBSCRIBE.getDescription());
            }
            stopWatch.stop();

            createRequestLog(applicationDO.getId(), serviceModuleDO.getServiceId(), basePageReqDTO.getServiceCode(), serviceModuleDO.getId()
                    , stopWatch.getTotalTimeMillis(), CommonBooleanEnum.TRUE.getValue(), basePageReqDTO.getAppKey());
        } catch (Exception e) {
            createRequestLog(Objects.isNull(applicationDO) ? 0 : applicationDO.getId()
                    , Objects.isNull(serviceModuleDO) ? 0 : serviceModuleDO.getServiceId(), basePageReqDTO.getServiceCode()
                    , Objects.isNull(serviceModuleDO) ? 0 : serviceModuleDO.getId()
                    , stopWatch.getTotalTimeMillis(), CommonBooleanEnum.FALSE.getValue(), basePageReqDTO.getAppKey());
            throw e;
        }

    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自定义注解可以用于实现AOP鉴权,以下是一个简单的示例代码,展示了如何使用自定义注解实现AOP鉴权。 首先,定义一个自定义注解 `@Authorization`: ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Authorization { String[] roles() default {}; } ``` 然后,在需要进行鉴权方法上添加 `@Authorization` 注解,并指定允许访问的角色列表: ```java public class MyService { @Authorization(roles = {"admin", "superuser"}) public void performAuthorizedAction() { // 执行需要鉴权的操作 } public void performUnauthenticatedAction() { // 执行无需鉴权的操作 } } ``` 接下来,创建一个切面类 `AuthorizationAspect`,在该类中使用 `@Around` 注解来拦截被 `@Authorization` 注解修饰的方法,并进行鉴权验证: ```java import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class AuthorizationAspect { @Around("@annotation(authorization)") public Object authorize(ProceedingJoinPoint joinPoint, Authorization authorization) throws Throwable { // 模拟鉴权逻辑 if (isUserAuthorized(authorization.roles())) { return joinPoint.proceed(); // 继续执行被拦截方法 } else { throw new UnauthorizedAccessException("Access denied"); // 抛出异常或执行其他处理 } } private boolean isUserAuthorized(String[] roles) { // 实际的鉴权逻辑,比如根据用户角色判断是否有权限访问 // 返回 true 表示有权限,返回 false 表示无权限 return true; } } ``` 最后,使用 Spring 或其他 AOP 框架来启用该切面,确保切面类被正确加载和生效。 通过以上步骤,你可以实现自定义注解用于AOP鉴权,对指定的方法进行权限验证。当调用被 `@Authorization` 注解修饰的方法时,会触发切面逻辑,在切面中进行鉴权验证,根据验证结果决定是否允许继续执行方法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值