怎么在SpringBoot中使用Spring AOP实现接口鉴权

面向切面编程

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

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

AOP的底层原理实现

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

实现了接口,使用JDK动态代理,生成的代理类会使用其接口没有实现接口,

使用CGlib动态代理,生成的代理类会集成被代理类

AOP的相关术语

连接点:被代理(被增强)的类中的方法

切入点:实际上需要被增强的方法

通知:要增强的逻辑代码

前置通知:在主体功能执行之前执行

后置通知:在主题功能执行之后执行

环绕通知:在主体功能执行前后执行

异常通知:在主题功能执行出现异常时执行

最终通知:主体功能无论执行是否成功都会执行

切面:切入点和切面的结合,即被增强的方法和增强的功能组成切面

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

注解:

@Aspect: 声明某个类是切面,编写通知、切入点

@Before: 对应前置通知

@AfterReturning: 对应后置通知

@Around: 对应环绕通知

@AfterThrowing: 对应异常通知

@After: 对应最终通知

@Pointcut: 声明切入点,标注在一个方法上可以让表达式更简洁

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

execution([权限修饰符][返回类型][类完全路径].[方法名称][参数列表类型])

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

实现接口鉴权

1. 配置yml文件

配置接口鉴权账密

account:  infos:    - account: xinchao      secret: admin

登录后复制

2. 读取账密配置

@Datapublic class SecretInfo {    private String account;    private String secret;}

登录后复制

3.编写接口鉴权方法

@Configuration@ConfigurationProperties("account")public class SecretConfig {    private List infos;    private Map map;    private Map tokenMap = new HashMap();    public void setInfos(List 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));    }}

登录后复制

@Datapublic 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)@Documentedpublic @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")@CaptchaIgnoreAoppublic 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进行鉴权即可。传入的位置是captcha字段

public class RequestWrapper 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实现接口鉴权的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2626122.html

(0)
上一篇 2025年3月7日 00:49:28
下一篇 2025年2月25日 22:32:26

AD推荐 黄金广告位招租... 更多推荐

相关推荐

发表回复

登录后才能评论