java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot Spring-AOP 接口鉴权

如何在SpringBoot中使用Spring-AOP实现接口鉴权

作者:心潮的滴滴

这篇文章主要介绍了如何在SpringBoot中使用Spring-AOP实现接口鉴权,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

面向切面编程

面向切面编程,可以将与业务无关但是需要被各个业务模块共同调用的逻辑抽取出来,以切面的方式切入到代码中,从而降低系统中代码的耦合度,减少重复的代码。

Spring AOP是通过预编译方式和运行期间动态代理实现程序面向切面编程

AOP的底层原理实现

AOP底层使用动态代理完成需求,为需要增加增强功能的类来生成代理类,有两种生成代理类的方式,对于被代理类(即需要增强的类),如果:

AOP的相关术语

相关注解以及切入点表达式

注解:

使用切入点表达式声明切入点

execution(* com.xxx.ABC.add()),对ABC类的方法进行增强

实现接口鉴权

1. 配置yml文件

配置接口鉴权账密

account:
  infos:
    - account: xinchao
      secret: admin

2. 读取账密配置

@Data
public class SecretInfo {
    private String account;
    private String secret;
}

3.编写接口鉴权方法

@Configuration
@ConfigurationProperties("account")
public class SecretConfig {
    private List<SecretInfo> infos;

    private Map<String, SecretInfo> map;

    private Map<String, TokenInfo> tokenMap = new HashMap<>();

    public void setInfos(List<SecretInfo> infos) {
        this.infos = infos;
        map = infos.stream().collect(Collectors.toMap(SecretInfo::getAccount, Function.identity()));
    }

    public synchronized String getToken(String account, String secret) {
        SecretInfo info = map.get(account);
        if (info == null) {
            throw new BusinessException("无效账号");
        }
        if (!StringUtils.equals(info.getSecret(), secret)) {
            throw new BusinessException("无效密码");
        }
        TokenInfo tokenInfo = tokenMap.get(account);
        if (tokenInfo != null && tokenInfo.getToken() != null) {
            return tokenInfo.getToken();
        }
        tokenInfo = new TokenInfo();
        String uuid = UUID.randomUUID().toString();
        tokenInfo.setToken(uuid);
        tokenInfo.setCreateDate(LocalDateTime.now());
        tokenInfo.setExpireDate(LocalDateTime.now().plusHours(2));
        tokenMap.put(account,tokenInfo);
        return tokenInfo.getToken();
    }

    public boolean checkCaptcha(String captcha) {
        return tokenMap.values().stream().anyMatch(e->StringUtils.equals(e.getToken(),captcha));
    }
}
@Data
public class TokenInfo {
    private LocalDateTime createDate;
    private LocalDateTime expireDate;
    private String token;

    public String getToken() {
        if (LocalDateTime.now().isBefore(expireDate)) {
            return token;
        }
        return null;
    }

    public boolean verification(String token) {
        return Objects.equals(this.token, token);
    }
}

4. 编写AOP

首先,编写一个注解来标识不需要鉴权

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CaptchaIgnoreAop {
}
@Slf4j
@Aspect
@Component
@Order(2)
public class CaptchaAop {

    @Value("${spring.profiles.active:dev}")
    private String env;

    @Autowired
    private SecretConfig config;

    @Pointcut("execution(public * com.herenit.phsswitch.controller.impl..*.*(..))" +
            "&&@annotation(org.springframework.web.bind.annotation.PostMapping)" +
            "&&!@annotation(com.herenit.phsswitch.aop.CaptchaIgnoreAop)")
    public void tokenAop() {
    }

    @Around("tokenAop()")
    public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        if (args.length == 0 || !(args[0] instanceof RequestWrapper)
                || "test,dev".contains(env)) {
            log.info("当前环境无需校验token");
            return joinPoint.proceed();
        }
        String captcha = ((RequestWrapper) joinPoint.getArgs()[0]).getCaptcha();
        if (!config.checkCaptcha(captcha)) {
            throw new BusinessException("captcha无效");
        }
        return joinPoint.proceed();
    }

}

5.编写接口测试

@PostMapping("/login")
@CaptchaIgnoreAop
public ResponseWrapper login(@RequestBody JSONObject userInfo) {
    String token = config.getToken(userInfo.getString("loginName")
            , userInfo.getString("password"));
    JSONObject result = new JSONObject();
    result.put("platformAccessToken", token);
    return ResponseWrapper.success(result);
}

通过这个接口,我们可以在内存中生成一个token,同时也会返回给前端。之后我们在调其他接口时传入这个token进行鉴权即可。传入的位置是captcha字段

public class RequestWrapper<T> implements Serializable {

    private static final long serialVersionUID = 8988706670118918321L;
    public RequestWrapper() {
        super();
    }

    private T args;

    private String captcha;

    private String funcode;

    public T getArgs() {
        return args;
    }

    public void setArgs(T args) {
        this.args = args;
    }

    public String getCaptcha() {
        return captcha;
    }

    public void setCaptcha(String captcha) {
        this.captcha = captcha;
    }

    public String getFuncode() {
        return funcode;
    }

    public void setFuncode(String funcode) {
        this.funcode = funcode;
    }
}

到此这篇关于如何在SpringBoot中使用Spring-AOP实现接口鉴权的文章就介绍到这了,更多相关 SpringBoot Spring-AOP 接口鉴权内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文