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"); } }
