使用springboot+aop实现用户的权限校验与日志的打印
Base切面
/**
* @Description 基础切面类
* @author xpWang
* @date 2020/1/6 16:13
*/
public class BaseAspect {
protected Method method;
protected Class clazz;
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || "
+ "@annotation(org.springframework.web.bind.annotation.GetMapping) || "
+ "@annotation(org.springframework.web.bind.annotation.PostMapping)||"
+ "@annotation(org.springframework.stereotype.Controller)||"
+ "@annotation(org.springframework.web.bind.annotation.RestController)")
void requestMapping() {
}
protected void init(JoinPoint joinPoint) throws NoSuchMethodException {
clazz = joinPoint.getTarget().getClass();
Signature signature = joinPoint.getSignature();
MethodSignature msg = (MethodSignature) signature;
method = clazz.getMethod(msg.getName(), msg.getParameterTypes());
}
}
权限校验父类
/**
* @Description 用户信息相关切面
* @author xpWang
* @date 2020/1/6 16:13
*/
@Slf4j
public class BaseTokenAspect extends BaseAspect{
@Autowired
private IAuthinfoService authinfoService;
protected String token;
protected AuthInfo authInfo;
@Override
protected void init(JoinPoint joinPoint) throws NoSuchMethodException {
super.init(joinPoint);
token = RequestUtil.getToken();
if (StringUtils.isNotEmpty(token)) {
try {
authInfo = authinfoService.getAuthInfo(token);
} catch (Exception e) {
log.warn("authinfoService getAuthInfo exceprtion :"+e);
}
}
}
protected ErrorCode checkToken() {
log.info("check auth.");
if (StringUtils.isEmpty(token)) {
return ErrorCode.TOKEN_NOTOKEN;
}
return authinfoService.checkToken(token);
}
protected Object[] getAuthinfoArgs(JoinPoint joinPoint) throws Exception {
Object[] args = joinPoint.getArgs();
int index=checkParameterHasAuth(method);
if (index!=-1){
log.info("set authinfo");
if (authInfo!=null){
args[index]=authInfo;
}else{
log.warn("there is no cache");
}
}
return args;
}
/**
* @Description 检查方法参数是否有cn.com.taiji.system.domain.rbac.AuthInfo
* @return int 返回参数AuthInfo所在Index,如果没有返回-1
* @author xpWang
* @date 2020/1/6 11:43
*/
private int checkParameterHasAuth(Method method){
Class<?>[] parameterTypes = method.getParameterTypes();
for(int i=0;i<parameterTypes.length;i++){
if (parameterTypes[i].isAssignableFrom(AuthInfo.class)){
return i;
}
}
return -1;
}
}
token验证切面
/**
* @Description 验证token注入auth
* @author xpWang
* @date 2020/1/6 16:14
*/
@Aspect
@Component
@Slf4j
@Order(1)
public class TokenMethodAspect extends BaseTokenAspect{
@Around("requestMapping()&&@annotation(cn.com.taiji.framework.annotation.TokenMethod)")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
try {
this.init(joinPoint);
Annotation[] annotations = method.getAnnotationsByType(TokenMethod.class);
if (ObjectUtils.isEmpty(annotations)) {
return joinPoint.proceed();
}
log.info("ClassName:\t" + clazz.getSimpleName()+"\tMethodName:\t" + method.getName());
ErrorCode errorCode=checkToken();
if (ErrorCode.TOKEN_CHECK_SUCCESS!=errorCode){
log.error(errorCode.toJsonString());
return new ObjectResponse(errorCode);
}
Object[] args=this.getAuthinfoArgs(joinPoint);
return joinPoint.proceed(args);
} catch (NoSuchMethodException e) {
return new ObjectResponse().error("token aspect init exception.");
} catch (Exception ex){
return new ObjectResponse().error("token aspect doarround exception",ex);
}
}
}
权限校验切面
/**
* @Description 验证token,permission注入auth
* @author xpWang
* @date 2020/1/6 16:14
*/
@Aspect
@Component
@Slf4j
@Order(2)
public class TokenPermissionMethodAspect extends BaseTokenAspect {
/**
* @Description 验证token, 注入Auth
* @author xpWang
* @date 2020/1/6 14:53
*/
@Around("requestMapping()&&@annotation(cn.com.taiji.framework.annotation.TokenPermissionMethod)")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
if (!RequestUtil.isNeedPermission()){
log.debug("checkAuthPermission isNeedPermission is false.");
return joinPoint.proceed();
}
try {
this.init(joinPoint);
log.info("ClassName:\t" + clazz.getSimpleName() + "\tMethodName:\t" + method.getName());
ErrorCode errorCode = checkToken();
if (ErrorCode.TOKEN_CHECK_SUCCESS != errorCode) {
log.error(errorCode.toJsonString());
return new ObjectResponse(errorCode);
}
ErrorCode perErrorCode = checkAuthPermission();
if (ErrorCode.SUCCESS!=perErrorCode){
log.error(perErrorCode.toJsonString());
return new ObjectResponse(perErrorCode);
}
log.info("permission verify success.");
TokenPermissionMethod annotation = method.getAnnotation(TokenPermissionMethod.class);
if (annotation.onlyCheck()){
return new ObjectResponse(ErrorCode.PERMISSION_CHECK_SUCCESS);
}
Object[] args = this.getAuthinfoArgs(joinPoint);
return joinPoint.proceed(args);
} catch (NoSuchMethodException e) {
return new ObjectResponse().error("token aspect init exception.");
} catch (Exception ex) {
return new ObjectResponse().error("TokenPermissionMethodAspect aspect doAround exception", ex);
}
}
/**
* @Description 检查用户权限
* @author xpWang
* @date 2020/1/6 15:49
*/
private ErrorCode checkAuthPermission(){
if (authInfo == null) {
return ErrorCode.PERMISSION_NO_CACHE;
}
Integer perId = RequestUtil.getPerId();
Integer nodeId = RequestUtil.getNodeId();
log.debug("checkAuthPermission perId:\t"+perId+"\tnodeId:\t"+nodeId);
//check permission
if (perId != null &&
(authInfo.getPermissions() == null || !ArrayUtils.contains(authInfo.getPermissions(), perId))) {
return ErrorCode.PERMISSION_FAILED;
}
if (nodeId != null &&
(authInfo.getNodes() == null || !ArrayUtils.contains(authInfo.getNodes(), nodeId))) {
return ErrorCode.PERMISSION_FAILED;
}
return ErrorCode.SUCCESS;
}
}
controller日志记录
这里的方法参数打印有问题,需要修改
@Aspect
@Component
@Slf4j
@Order(1)
public class ControllerLogAspect extends BaseAspect{
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || "
+ "@annotation(org.springframework.web.bind.annotation.GetMapping) || "
+ "@annotation(org.springframework.web.bind.annotation.PostMapping)")
void requestLog() {
}
@Around("requestLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long begin=System.currentTimeMillis();
init(joinPoint);
log.debug("BEGIN:\tClassName:\t" + clazz.getSimpleName()+"\tMethodName:\t" + method.getName()+"\targs:\t"+JSON.toJSONString(joinPoint.getArgs(), SerializerFeature.WriteMapNullValue));
//log.debug("BEGIN:\tClassName:\t" + clazz.getSimpleName()+"\tMethodName:\t" + method.getName()+"\targs:\t");
Object result=joinPoint.proceed();
log.debug("END:\tClassName:\t" + clazz.getSimpleName()+"\tMethodName:\t" + method.getName()+"\tCost:"+(System.currentTimeMillis()-begin)+"ms\tResult"+JSON.toJSONString(result));
return result;
}
}
annotation
/**
* @Description 需要进行Token以及权限验证的Controller注解
* @author xpWang
* @date 2020/1/6 11:27
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TokenPermissionMethod {
boolean onlyCheck() default false;
}
/**
* @Description 需要进行Token验证的Controller注解
* @author xpWang
* @date 2020/1/6 11:27
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TokenMethod {
}
controller使用
/**
* @Description 用户登录信息相关服务
* @author xpWang
* @date 2019/12/31 10:23
*/
@RestController
@RequestMapping("/authinfo")
@Api(tags = "账户权限管理系统-用户认证", value = "authinfo")
public class AuthInfoController extends BaseController {
@Autowired
private IAuthinfoService authinfoService;
@PostMapping("/login")
@ApiOperation(notes = "登录接口", value = "login")
public AjaxResponse login(@RequestBody UserDO user) {
ObjectResponse response=new ObjectResponse();
AuthInfo auth = null;
try {
auth = authinfoService.login(user);
if (auth == null) {
return response.error("Incorrect user name or password");
}
return response.success("login success", auth);
} catch (Exception e) {
return response.error("login exception : " , e);
}
}
/**
* @Description AOP判断了
* @author xpWang
* @date 2020/1/6 16:14
*/
@PostMapping("/checkAuth")
@ApiOperation(notes = "登录信息权限校验", value = "checkAuth")
@TokenPermissionMethod(onlyCheck = true)
public AjaxResponse checkAuth() {
return new ObjectResponse(ErrorCode.PERMISSION_CHECK_SUCCESS);
}
/**
* 根据TOKEN获取账号信息
*/
@PostMapping("/getAuthInfo")
@ApiOperation(notes = "账号分页查询", value = "getAuthInfo")
@TokenMethod
public AjaxResponse getAuthInfo(AuthInfo authInfo) {
ObjectResponse response=new ObjectResponse();
try {
if (authInfo != null) {
return response.success("success.", authInfo);
} else {
return response.error("there is no authinfo in cache.");
}
} catch (Exception e) {
e.printStackTrace();
return response.error("getAuthInfo exception:\t",e);
}
}
public AuthInfoController(){
System.out.println("init AuthInfoController.");
}
}