自定义注解 @CheckLogin
Controller
@GetMapping("/users/{id}")
@CheckLogin
public User findById(@PathVariable Integer id) {
return userMapper.selectByPrimaryKey(id);
}
1. 添加自定义注解接口
/**
* 自定义注解接口
*/
public @interface CheckLogin {
}
2. 编写aop,实现校验逻辑
import com.example.usercenter.utils.JwtOperator;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* aop
*/
@Aspect
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CheckLoginAspect {
private final JwtOperator jwtOperator;
@Around("@annotation(com.example.usercenter.auth.CheckLogin)")
public Object checkLogin(ProceedingJoinPoint point) {
// TODO 在这里编写自己业务的校验逻辑
try {
// 1.从header里面获取token
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = ((ServletRequestAttributes) requestAttributes);
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("X-Token");
// 2.校验token是否合法,不合法则直接抛出异常,合法则放行
Boolean isValid = jwtOperator.validateToken(token);
if (!isValid) {
throw new SecurityException("Token不合法");
}
// 3. 校验成功,将用户信息设置到request的attribute里面
Claims claims = jwtOperator.getClaimsFromToken(token);
request.setAttribute("id", claims.get("id"));
request.setAttribute("role", claims.get("role"));
// 校验通过
return point.proceed();
} catch (Throwable throwable) {
// 校验不通过
throw new SecurityException("Token不合法");
}
}
}
3. 添加SecurityException异常捕捉,返回json错误信息
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常捕捉
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionErrorHandler {
/**
* 捕捉指定SecurityException异常
*
* @param e SecurityException
* @return ResponseEntity<JsonResult>
*/
@ExceptionHandler(SecurityException.class)
public ResponseEntity<JsonResult> error(SecurityException e) {
log.warn("发生SecurityException异常", e);
return new ResponseEntity<>(JsonResult.builder()
.code(HttpStatus.UNAUTHORIZED.value())
.msg("请登录后再进行访问!")
.build(),
HttpStatus.UNAUTHORIZED);
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class JsonResult {
private Integer code;
private String msg;
private Object date;
}
header不添加X-Token调用接口,返回数据:
Feign自定义拦截器传递header
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 自定义拦截器,获取header参数并进行传递
*/
public class TokenRelayRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
// 1. 获取到token
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = ((ServletRequestAttributes) requestAttributes);
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("X-Token");
// 2.将token传递
if (StringUtils.isNotBlank(token)) {
requestTemplate.header("X-Token", token);
}
}
}
在配置文件中添加
feign:
client:
config:
# 全局配置
default:
# 日志级别(NONE,BASIC,HEADERS,FULL)
loggerLevel: full
requestInterceptors:
- com.example.contentcenter.feignclient.interceptor.TokenRelayRequestInterceptor
将拦截器注册为feign全局配置
这样,feign在调用需要登录的接口时,就会将header中X-Token参数携带过去了