文章目录
- 一、简要概述
- 二、实现过程
- 1. pom引入依赖
- 2. 自定义注解
- 3. 定义切面
- 4. 定义权限检查逻辑
- 三、注解使用
- 四、运行结果
- 五、源码放送
一、简要概述
Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。我们借助expireAfterWrite
过期时间设置和springboot的自定义注解、切面等技术来打造最简单的接口鉴权系统。
二、实现过程
1. pom引入依赖
在原有springboot基础上引入切面、guava依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
2. 自定义注解
import java.lang.annotation.Documented;
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)
@Documented
public @interface AuthToken
{
}
3. 定义切面
在aop的逻辑内,先走@Around注解的方法。然后是@Before注解的方法,然后这两个都通过了,走核心代码,核心代码走完,无论核心有没有返回值,都会走@After方法。然后如果程序无异常,正常返回就走@AfterReturn,有异常就走@AfterThrowing。
我们这里使用了 @Before:前置通知,在调用目标方法之前执行检查
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.fly.core.exception.ValidateException;
import com.fly.core.utils.HttpServletUtils;
import com.fly.demo.aspect.annotation.AuthToken;
import com.fly.demo.service.TokenService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Order(0)
@Component
public class AuthTokenAspect
{
@Autowired
TokenService tokenService;
/**
* 使用AuthToken注解标注的类
*
*/
@Before("@annotation(authToken)")
public void doBefore(JoinPoint joinPoint, AuthToken authToken)
{
HttpServletRequest request = HttpServletUtils.getRequest();
if (request == null)
{
log.error("AuthToken注解使用错误,当前请求非web请求");
}
log.info("开始执行鉴权检查");
String token = request.getHeader("token");
if (!tokenService.valide(token))
{
throw new ValidateException("对不起,您无权访问该接口,请检查token参数");
}
}
}
4. 定义权限检查逻辑
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class TokenService
{
/**
* 30分钟失效
*/
Cache<String, String> cache = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).build();
/**
* 验证token是否合法
*
* @param token
*/
public boolean valide(String token)
{
return StringUtils.equals(token, getToken());
}
/**
* 获取sysToken
*/
private String getToken()
{
String sysToken = cache.getIfPresent("token");
if (sysToken == null)
{
sysToken = UUID.randomUUID().toString().replace("-", "");
log.info("------ now valid sysToken is: {}", sysToken);
cache.put("token", sysToken);
}
return sysToken;
}
}
三、注解使用
我们在需要执行权限检查的地方添加@AuthToken
即可
@AuthToken
@ApiOperation("刷新欢迎语")
@PostMapping("/refresh")
@ApiImplicitParam(name = "message", value = "欢迎语", allowableValues = "骝马新跨白玉鞍,战罢沙场月色寒。城头铁鼓声犹震,匣里金刀血未干。,活捉洪真英,生擒李知恩! ", required = true)
public JsonResult<?> refresh(@RequestHeader String token, String message)
{
if (StringUtils.isBlank(message))
{
return JsonResult.error("message不能为空");
}
boolean success = updateWelcomeMsg(message) > 0;
return success ? JsonResult.success(message) : JsonResult.error("刷新欢迎语失败");
}
四、运行结果
token不合法提示
后台查看token
请求头填入合法token
接口调用成功
五、源码放送
https://gitcode.com/00fly/springboot-demo/overview
有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!
-over-