SpringBoot项目中通过注解实现Aop编程实战。
项目结构如图:
项目实现:在接口前构造aop切面,实现不同身份用户的鉴权
1、新建maven工程testAspect
然后在pom文件中引入aop依赖和其他基础依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
此处没有写版本,是因为引入了springboot的parent:spring-boot-starter-parent
2、新建一个自定义注解AuthToken
注解:AuthToken
后面实现被AuthToken注解的方法都是切点(Pointcut)
自定义注解参考:java自定义注解@annotation
package com.tzq.aspect.annotation;
import java.lang.annotation.*;
/**
* @Author tangzhiqian
* @CreateTime 2021/6/8 15:31
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthToken {
/**
* 访问所需的身份,默认为空,为登录即可访问,可以多个定义
*
*/
String[] role_name() default "";
}
3、新建MyController类
该类中写了三个接口:无需验证的登录、普通user登录、管理员admin登录
在user登录接口方法上面加上注解@AuthToken
在admin登录接口方法上面加上注解@AuthToken(role_name = {“admin”, “Administrator”})
package com.tzq.aspect.controller;
import com.tzq.aspect.annotation.AuthToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author tangzhiqian
* @CreateTime 2021/6/8 15:31
*/
@RestController
public class MyController {
/**
* 无需校验,不加注解
*/
@GetMapping("hello")
public String hello(Integer id, String name, Integer age) {
System.out.println("hello方法执行:id==>" + id + ",name==>" + name + ",age==>" + age);
return "hi~ 我不需要用户权限";
}
/**
* 需要登录校验,加上注解,但不传所需角色
*/
@GetMapping("user")
@AuthToken
public String user(Integer id, String name, Integer age) {
System.out.println("user方法执行:id==>" + id + ",name==>" + name + ",age==>" + age);
return "hi~ 我需要登陆后才可以访问";
}
/**
* 需要角色校验,加上注解,并且写入两个角色,本文演示两个角色有一个即可访问,当然写一个可以。
* 注:若想两个角色同时具有,修改后文的逻辑判断即可。
* 若需要更复杂的逻辑操作,推荐使用Spring Security框架。
*/
@GetMapping("admin")
@AuthToken(role_name = {"admin", "Administrator"})
public String admin(Integer id, String name, Integer age) {
System.out.println("admin方法执行:id==>" + id + ",name==>" + name + ",age==>" + age);
return "hi~ 我需要管理员身份才可以访问";
}
}
4、新建切片类:
AuthTokenAspect.class,在类上加注解@Aspect表示这是该类是切面。
一个切面类中,可以有多个切点和切点执行的方法
package com.tzq.aspect.aspect;
import com.tzq.aspect.annotation.AuthToken;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @Author tangzhiqian
* @CreateTime 2021/6/8 15:33
*/
@Aspect
@Component
public class AuthTokenAspect {
/**
* Spring中使用@Pointcut注解来定义方法切入点
*
* @Pointcut 用来定义切点,针对方法。后面的aop增强均是围绕切入点来完成的
* @Aspect 用来定义切面,针对类。
* 此处仅配置被我们刚才定义的注解:AuthToken修饰的方法即可
*
*/
@Pointcut("@annotation(authToken)")
public void doAuthToken(AuthToken authToken) {
}
/**
* 此处我使用环绕增强,在方法执行之前或者执行之后均会执行。
*/
@Around("doAuthToken(authToken)")
public Object deArrond(ProceedingJoinPoint pjp, AuthToken authToken) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 获取访问该方法所需的role_name信息
String[] role_name = authToken.role_name();
if (role_name[0].equals("")){ //role_name没写,默认是“”,长度为1
// 只需登录,验证是否具有id即可。
String id = request.getParameter("id");
/**
* 此处使用短路与,若id==null直接会执行if体,不会继续判断
* 若不等于null,则去验证后面的条件,但是也不会出现因为id为null而出现的空指针异常
* 所以这样写也是安全的。
*/
if (id != null && !id.equals("")) {
// 已登录,执行原方法并返回即可。
return pjp.proceed();
}
// 未登录,不执行方法,直接返回错误信息
return "请登陆后再试!";
} else {
// 需要验证身份
String role = request.getParameter("name");
for (String str : role_name) {
/**
* 此处str由于是用role_name中取值,则str必定不为空
* 而从请求头中获取的role有可能为空,则此处调用str的equals方法
* 当然可以直接在获得请求头后进行验证是是否不为空。
*/
if (str.equals(role)) {
// 身份匹配成功
return pjp.proceed();
}
}
return "权限校验失败,不具有指定的身份";
}
}
}
到这里,该aop切面编写完成!测试一下:
http://localhost:8077/user
http://localhost:8077/user?name=admin&id=1
实现了用户身份认证!!!