content: package com.ncst.seckill.access;
  
  import com.alibaba.fastjson.JSON;
  import com.ncst.seckill.key.prefix.AccessKey;
  import com.ncst.seckill.pojo.SkUser;
  import com.ncst.seckill.result.CodeMsg;
  import com.ncst.seckill.result.Result;
  import com.ncst.seckill.service.IRedisService;
  import com.ncst.seckill.service.IUserService;
  import com.ncst.seckill.service.impl.UserServiceImpl;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  import org.springframework.web.method.HandlerMethod;
  import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  import org.thymeleaf.util.StringUtils;
  
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import java.io.IOException;
  import java.io.OutputStream;
  
  /**
   * @Date 2020/10/19 15:10
   * @Author by LSY
   * @Description
   */
  @Service
  public class LoginInterceptor extends HandlerInterceptorAdapter {
  
      @Autowired
      private IUserService userService;
  
      @Autowired
      private IRedisService redisService;
  
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
          if (handler instanceof HandlerMethod) {
              SkUser user = getUser(request, response);
              UserContext.setUserHolder(user);
              HandlerMethod hm = (HandlerMethod) handler;
              AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
              if (accessLimit == null) {
                  return true;
              }
              int seconds = accessLimit.seconds();
              int maxCount = accessLimit.maxCount();
              boolean needLogin = accessLimit.needLogin();
              String key = request.getRequestURI();
              if (needLogin) {
                  if (user == null) {
                      render(response, CodeMsg.SESSION_ERROR);
                      return false;
                  }
                  key += "_" + user.getId();
              } else {
                  // do nothing
              }
              AccessKey ak = AccessKey.withExpire(seconds);
              Integer count = redisService.get(ak, key, Integer.class);
              if (count == null) {
                  redisService.set(ak, key, 1);
              } else if (count < maxCount) {
                  redisService.incr(ak, key);
              } else {
                  render(response, CodeMsg.ACCESS_LIMIT_REACHED);
                  return false;
              }
          }
          return true;
      }
  
      /**
       *  像页面发出错误消息
       * @param response response
       * @param sessionError 发送的错误消息
       * @throws IOException exception
       */
      private void render(HttpServletResponse response, CodeMsg sessionError) throws IOException {
          response.setContentType("application/json;charset=UTF-8");
          OutputStream out = response.getOutputStream();
          String str = JSON.toJSONString(Result.error(sessionError));
          out.write(str.getBytes("UTF-8"));
          out.flush();
          out.close();
      }
  
      private SkUser getUser(HttpServletRequest request, HttpServletResponse response) {
          String paramToken = request.getParameter(UserServiceImpl.COOKIE_NAME_TOKEN);
          String cookieToken = getCookieValue(request);
          if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
              return null;
          }
          //优先使用
          String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
          return userService.getByToken(response, token);
      }
  
      /**
       * 获取cookie 值
       *
       * @param request req
       * @return cookie
       */
      private String getCookieValue(HttpServletRequest request) {
          Cookie[] cookies = request.getCookies();
          if (cookies == null || cookies.length <= 0) {
              return null;
          }
          for (Cookie cookie : cookies) {
              if (cookie.getName().equals(UserServiceImpl.COOKIE_NAME_TOKEN)) {
                  return cookie.getValue();
              }
          }
          return null;
      }
  }
  