由于登录是通用的模块, 所以需要写一个公共的类可以方便的调用
如果APP所有的应用都是需要登录才能进行访问的话,此时可以使用过滤器进行编写, 在访问之前拦截接口,校验是否有登录, 也可以使用SpringSecurity框架来进行实现
以下使用aop方式实现全局校验
第一步自定义注解类作为切点
package com.fish.pojo.annotation;
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;
/**
* 校验客户端登录标记
*/
@Documented//是 java 在生成文档时,是否显示该注解的开关。
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Target({ElementType.TYPE,ElementType.METHOD})//用于描述方法
public @interface CheckClientOline {
}
第二步编写aop的管道接口(可以多实现该接口)
package com.fish.aop;
import org.aspectj.lang.JoinPoint;
/**
* 切面管道接口
*/
public interface AopChannel {
/**
* 执行
* @param joinPoint
* @throws Exception
*/
public void exec(JoinPoint joinPoint) throws Exception;
}
实现切面接口(可以校验管理员等其他验证身份)
package com.fish.aop.channel;
import com.fish.aop.AopChannel;
import com.fish.common.aop.AopUtils;
import com.fish.common.security.SecurityUtils;
import com.fish.common.security.entity.LoginUser;
import com.fish.common.servlet.ServletUtils;
import com.fish.pojo.annotation.CheckClientOline;
import com.fish.pojo.exception.OffLineException;
import org.aspectj.lang.JoinPoint;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* 校验用户端用户是否在线
*/
public class CheckClientOlineChannel implements AopChannel{
@Override
public void exec(JoinPoint joinPoint) throws Exception {
Class<?> type = AopUtils.getType(joinPoint);
HttpServletRequest request = ServletUtils.getRequest();
CheckClientOline checkOline = type.getAnnotation(CheckClientOline.class);
LoginUser user = SecurityUtils.getHeaderUser(request, LoginUser.class);
if (user!=null){
request.setAttribute(SecurityUtils.APP_USER, user);
}
if(checkOline == null) {
Method method = AopUtils.getMethod(joinPoint);
checkOline = method.getAnnotation(CheckClientOline.class);
}
if(checkOline == null)
return;
if(user == null)
throw new OffLineException("登录失效");
if(user.getUserStatus() != LoginUser.getUserStatusDict().get("用户端"))
throw new OffLineException("只有用户才可以访问此权限");
request.setAttribute(SecurityUtils.APP_USER, user);
}
}
编写aop切面配置类
package com.fish.config;
import com.alibaba.fastjson.JSON;
import com.fish.aop.AopChannel;
import com.fish.aop.channel.CheckAdminOlineChannel;
import com.fish.aop.channel.CheckClientOlineChannel;
import com.fish.aop.channel.CheckClientSignChannel;
import com.fish.common.servlet.ServletUtils;
import com.fish.dao.redis.RedissonDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
* aop切面
*
* @author chenwei
* @date 2019年6月28日 下午3:50:37
*/
@Aspect
@Component
public class ControllerAopConfig {
private static final Logger log = Logger.getLogger(ControllerAopConfig.class);
@Value("${controller.log.show.enable}")//是否需要打印日志的配置
private boolean isShowControllerLog;
@Autowired
private RedissonDao redisson;
private List<AopChannel> aopchannels = new ArrayList<AopChannel>(9) {
private static final long serialVersionUID = -689595264093084192L;
{
add(new CheckAdminOlineChannel());//管理员
add(new CheckClientOlineChannel());//客户端用户
add(new CheckClientSignChannel());//签名
}
};
/**
* 指定切入的路径
* @author chenwei
* @date 2019年6月28日 下午3:52:17
*/
@Pointcut("execution(public * com.fish.controller..*.*(..))")
public void controllerAop() {
}
/**
* 在目标业务方法执行之前执行
* @param joinPoint
* @throws Exception
*/
@Before("controllerAop()")
public void doBefore(JoinPoint joinPoint) throws Exception {
printLog(joinPoint);
//执行校验的方法
for (AopChannel aopChannel : aopchannels) {
aopChannel.exec(joinPoint);
}
}
/**
* 在目标业务方法返回结果之后执行
* @param ret
* @throws Throwable
*/
@AfterReturning(returning = "ret",pointcut = "controllerAop()")
public void doAfterReturning(Object ret) throws Throwable {
redisson.unlock();
}
/**
* 打印日志
* @param joinPoint
*/
private void printLog(JoinPoint joinPoint) {
if (!isShowControllerLog){
return;
}
try {
HttpServletRequest request = ServletUtils.getRequest();
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getName();
log.info("=====================new Request======================");
log.info("-----logger aop"+log);
log.info("Request URL:"+request.getRequestURL());
Object[] args = joinPoint.getArgs();
log.info("params: ");
if (args!=null){
for (Object arg : args) {
if (
arg instanceof ServletResponse ||
arg instanceof ServletRequest ||
arg instanceof InputStreamSource
){
//不打印
continue;
}else {
log.info(" "+ JSON.toJSONString(arg));
}
}
}
log.info("UserKey:"+ request.getHeader("UserKey"));
log.info("Class Method:"+className+"."+methodName+"()"+"From IP:"+request.getRemoteAddr());
System.out.println(log);
log.info("======================================================");
}catch (Exception e){
// e.printStackTrace();
}
}
}