在线用户双重判断

一、用户是否在线校验(双重保障)

先经过注解进入全局拦截器;再通过异常处理器来处理

方式一:通过面向切面的思想,使用注解接口来拦截,需要传递request对象,才可以获取用户信息(全局拦截器处理)

方式二:通过全局对象(不需要传参),获取当前request对象,request对象再通过用户数据来判断用户是否在线(全局异常处理)

1.1 控制层(获取角色和权限数据)

/**
 * 	获取用户的角色和权限数据
 * @author HuangJingNa
 * @date 2019年12月22日 下午4:01:55
 *
 * @return
 * @throws Exception 
 */
@PostMapping("find_role_permission")
@CheckRoles({"role:student"})
@CheckPerssions({"permission:study", "permission:sleep"})
public Object findRolePerssion() throws Exception {
	return userService.findRolePerssion();
}

1.2 进入全局拦截器(注解)

package cn.kooun.core.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import cn.kooun.service.UserService;

/**
 * 	全局拦截器
 * @author HuangJingNa
 * @date 2019年12月22日 下午4:40:45
 *
 */
public class GlobalInterceptor implements HandlerInterceptor{
	@Autowired
	private UserService userService;
	
	@Override
	public boolean preHandle(
			HttpServletRequest request, 
			HttpServletResponse response, 
			Object handler) throws Exception {
		if(handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			return baseHandler(request, response, handlerMethod);
		}
		return true;
	}
	private boolean baseHandler(
			HttpServletRequest request, 
			HttpServletResponse response, 
			HandlerMethod handlerMethod) {
		boolean flag = true;
		flag = userService.checkOnline(request, response, handlerMethod);
		if(!flag) {
			return flag;
		}
		flag = userService.checkRoles(request, response, handlerMethod);
		if(!flag) {
			return flag;
		}
		flag = userService.checkPerssions(request, response, handlerMethod);
		if(!flag) {
			return flag;
		}
		return flag;
	}
}

不管是否有该注解,都会进入全局拦截器中

1.3 service层CheckOnline()中需要将登录时封装的用户对象设置在request域中

	 /** 	
	  *    校验是否在线
	 * @author HuangJingNa
	 * @date 2019年12月22日 下午4:48:13
	 *
	 * @param request
	 * @param response
	 * @param handlerMethod
	 * @return
	 */
	public boolean checkOnline(
			HttpServletRequest request, 
			HttpServletResponse response, 
			HandlerMethod handlerMethod) {
		//获取方法上的注解,判断是否要进行校验
		NotCheckOnline notCheckOnline = handlerMethod.getMethodAnnotation(NotCheckOnline.class);
		if(notCheckOnline != null) {
			//放行,不进行校验
			return true;
		}
		
		//获取在线用户
		Object user = RequestUtils.getUserLogin(request, response, redisService);
		if(user == null) {
			ResponseUtils.returnJson(
					response, 
					ResultUtils.error("登录失效,请重新登录~", Result.JUMP_LOGIN));
			return false;
		}
		//设置request.setAttribute(),方便全局校验获取用户数据
		request.setAttribute(Dict.USER, user);
		
		return true;
	}
请求类RequestUtils
package cn.kooun.common.request;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.StringUtils;

import cn.kooun.common.redis.RedisService;
import cn.kooun.pojo.info.Dict;

/**
 * 	请求工具类
 * @author HuangJingNa
 * @date 2019年12月22日 下午4:52:10
 *
 */
public class RequestUtils {
	/**
	 * 	校验用户是否在线(根据用户凭证)
	 * @author HuangJingNa
	 * @date 2019年12月22日 下午5:03:40
	 *
	 * @param request
	 * @param response
	 * @param redisService
	 * @return
	 */
	public static Object getUserLogin(
			HttpServletRequest request, 
			HttpServletResponse response,
			RedisService redisService) {
		//登录校验
		String userToken = request.getHeader(Dict.USER_TOKEN);
		if(StringUtils.isEmpty(userToken)) {
			return null;
		}
		//返回在线数据
		return redisService.get(userToken);
	}
	
}
相应类ReponseUtils
package cn.kooun.common.reponse;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;

import cn.kooun.pojo.info.Dict;

/**
 * 	响应工具类
 * @author HuangJingNa
 * @date 2019年12月22日 下午4:52:24
 *
 */
public class ResponseUtils {
	/**
	 * response响应json数据格式
	 * 
	 * @author HuangJingNa
	 * @date 2019年12月22日 下午4:52:24
	 * @param response
	 * @param result
	 */
	public static void returnJson(HttpServletResponse response, Object result) {
		//创建json转换的类
		PrintWriter writer = null;
		try {
			// 避免乱码
			response.setCharacterEncoding(Dict.UTF8);
			// 设置ContentType
			response.setContentType(Dict.JSON_HEAD);
			writer = response.getWriter();
			writer.append(JSON.toJSONString(result));
			writer.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(writer!=null) {
				writer.close();
			}
		}
	}
}
使用全局对象获取用户对象时才有值
	 /**
	 * 	获取用户的角色和权限数据
	 * @author HuangJingNa
	 * @date 2019年12月22日 下午4:03:19
	 *
	 * @return
	 * @throws Exception 
	 */
	public Object findRolePerssion() throws Exception {
		//使用全局对象来判断用户是否在线
		LoginUser user = (LoginUser) SecurityUtils.getCurrentUser();
		return packageRolesAndPermissions(user);
	}
	/**
	 * 	打包角色和权限数据
	 * @author HuangJingNa
	 * @date 2019年12月22日 下午4:30:49
	 *
	 * @param user
	 * @return
	 */
	private Object packageRolesAndPermissions(LoginUser user) {
		//在线:获取权限和角色
		List<String> roles = user.getRoles();
		List<String> permissions = user.getPermissions();
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("roles", roles);
		result.put("permissions", permissions);
		return ResultUtils.success(result);
	}

1.4 权限工具SecurityUtils

package cn.kooun.common;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.kooun.pojo.exception.OffLineException;
import cn.kooun.pojo.info.Dict;

/**
 * 	权限工具
 * @author HuangJingNa
 * @date 2019年12月23日 下午2:44:54
 *
 */
public class SecurityUtils {
	/**
	 * 	获取当前用户
	 * 	可以作为全局对象来获取当前request对象,
	 * 	再使用request对象(通过用户key值)来获取用户数据,来判断用户是否登录
	 * 	方式一:通过注解接口的方式来判断用户是否在线(根据用户凭证);全局拦截器处理
	 * 	方式二:使用全局对象来获取request对象;全局异常处理
	 * 	以上两个方式,双重保障
	 * @author HuangJingNa
	 * @date 2019年12月23日 下午2:46:39
	 *
	 * @return
	 * @throws ffLineException 
	 */
	public static Object getCurrentUser() throws Exception {
		HttpServletRequest request = 
				((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
				.getRequest();
		Object user = request.getAttribute(Dict.USER);
		if(user == null) {
			throw new OffLineException("用户不在线~");
		}
		return user;
	}
}

1.5 用户不在线异常处理OffLineException

package cn.kooun.pojo.exception;
/**
 * 	自定义异常,用户不在线抛出的异常
 * @author HuangJingNa
 * @date 2019年12月23日 下午2:55:38
 *
 */
public class OffLineException extends Exception{

	private static final long serialVersionUID = 7291020619358516087L;

	public OffLineException() {
		super();
	}

	public OffLineException(String message) {
		super(message);
	}
	
}

1.6 全局拦截器处理该自定义异常

package cn.kooun.core.exception;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.kooun.common.result.Result;
import cn.kooun.common.result.ResultUtils;
import cn.kooun.pojo.exception.OffLineException;

/**
 *	全局异常处理
 * @author HuangJingNa
 * @date 2019年12月21日 下午3:46:19
 *
 */
@ControllerAdvice//标记此类为全局异常拦截器
public class GlobalExceptionHandler {
	/**
	 * 	系统异常处理,如404、500
	 * @author HuangJingNa
	 * @date 2019年12月21日 下午3:48:45
	 *
	 * @return
	 * @throws Exception
	 */
	@ExceptionHandler(value = Exception.class)//监听对应的异常对象
	@ResponseBody
	public Object defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception{
		//控制台输出错误信息
		e.printStackTrace();
		if(e instanceof OffLineException) {
			return ResultUtils.error("登录失效,请重新登录~", Result.JUMP_LOGIN);
		}
		return ResultUtils.error("系统繁忙,请联系管理员~");
	}
}
原文地址:https://www.cnblogs.com/nadou/p/14003920.html