1.在spring-mvc.xml中添加一下配置
<!-- 拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/cmp/*" /> <!-- 访问路径 -->
<bean class="com.core.utils.APIInterceptor" /> <!-- 拦截器所在的类 -->
</mvc:interceptor>
</mvc:interceptors>
2.创建Token实体类
/** * Token的Model类,可以增加字段提高安全性,例如时间戳、url签名 * @author liuwei * */ public class Token { // 用户id private String userId; // 随机生成的uuid private String token; public Token(String userId, String token) { this.userId = userId; this.token = token; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } @Override public String toString() { return "Token [userId=" + userId + ", token=" + token + "]"; } }
3.创建token的service层
public interface TokenService { /** * 创建一个token关联上指定用户 * @param userId 指定用户的id * @return 生成的token */ public Token createToken(String userId); /** * 检查token是否有效 * @param model token * @return 是否有效 */ public boolean checkToken(Token model); /** * 从字符串中解析token * @param authentication 加密后的字符串 * @return */ public Token getToken(String authentication); }
import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.core.bean.Token; import com.core.service.TokenService; import com.core.utils.Constants; @Service public class TokenServiceImpl implements TokenService { @Autowired private JedisClientCluster jedisClientCluster; public Token createToken(String userId) { //使用uuid作为源token String token = UUID.randomUUID().toString().replace("-", ""); Token model = new Token(userId, token); //加入redis缓存 jedisClientCluster.set(userId, token); //jedisClientCluster.expire(userId, Constants.TOKEN_EXPIRES_SECONDS); return model; } public Token getToken(String authentication) { if (authentication == null || authentication.length() == 0) { return null; } String[] param = authentication.split("_"); if (param.length != 2) { return null; } //使用userId和源token简单拼接成的token,可以增加加密措施 String userId = param[0]; String token = param[1]; return new Token(userId, token); } public boolean checkToken(Token model) { if (model == null) { return false; } String token = jedisClientCluster.get(model.getUserId()); if (token == null || !token.equals(model.getToken())) { return false; } // 如果验证成功,说明此用户进行了一次有效操作,延长token的过期时间 jedisClientCluster.expire(model.getUserId(), Constants.TOKEN_EXPIRES_SECONDS); return true; } }
4.创建com.core.utils.APIInterceptor类import java.lang.reflect.Method;
import java.util.UUID; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.core.annotation.Authorization; import com.core.bean.Token; import com.core.service.TokenService; @Component public class APIInterceptor extends HandlerInterceptorAdapter { private static final Log log = LogFactory.getLog(APIInterceptor.class); @Resource private TokenService tokenService; @Override
//拦截方法执行前,调用的方法,ture通过。false结束 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); com.sensing.core.annotation.Token annotation = method.getAnnotation(com.sensing.core.annotation.Token.class); if (annotation != null) { boolean needSaveSession = annotation.save(); if (needSaveSession) { request.getSession(true).setAttribute("token", UUID.randomUUID().toString()); } boolean needRemoveSession = annotation.remove(); if (needRemoveSession) { if (isRepeatSubmit(request)) { log.info("please don't repeat submit,url:"+ request.getServletPath()); return false; } request.getSession(true).removeAttribute("token"); } } //从header中得到token String authorization = request.getHeader(Constants.AUTHORIZATION); if(authorization == null){ log.warn("token不存在"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } //验证token Token model = tokenService.getToken(authorization); log.info("拦截到的token:"+model.toString()); if (tokenService.checkToken(model)) { //如果token验证成功,将token对应的用户id存在request中,便于之后注入 request.setAttribute(Constants.CURRENT_USER_ID, model.getUserId()); return true; } //如果验证token失败,并且方法注明了Authorization,返回401错误 if (method.getAnnotation(Authorization.class) != null) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } return true; } else { return true; } } //防止重复提交 private boolean isRepeatSubmit(HttpServletRequest request) { String serverToken = (String) request.getSession(true).getAttribute("token"); if (serverToken == null) { return true; } String clinetToken = request.getParameter("token"); if (clinetToken == null) { return true; } if (!serverToken.equals(clinetToken)) { return true; } return false; } @Override
// 拦截方法执行后,调用的方法 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("3"); } }