spring mvc+jwt+vue js 验证
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>2.3.1</version> </dependency>
public class JWT { private static final String SECRET = "X1243"; private static final String EXP = "exp"; private static final String PAYLOAD = "payload"; //加密,传入一个对象和有效期 public static <T> String sign(T object, long maxAge) { try { final JWTSigner signer = new JWTSigner(SECRET); final Map<String, Object> claims = new HashMap<String, Object>(); ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(object); claims.put(PAYLOAD, jsonString); claims.put(EXP, System.currentTimeMillis() + maxAge); return signer.sign(claims); } catch(Exception e) { return null; } } //解密,传入一个加密后的token字符串和解密后的类型 public static<T> T unsign(String jwt, Class<T> classT) { final JWTVerifier verifier = new JWTVerifier(SECRET); try { final Map<String,Object> claims= verifier.verify(jwt); if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) { long exp = (Long)claims.get(EXP); long currentTimeMillis = System.currentTimeMillis(); if (exp > currentTimeMillis) { String json = (String)claims.get(PAYLOAD); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(json, classT); } } return null; } catch (Exception e) { return null; } } }
public class ResponseUtil { public static String SUCCESS = "0"; public static String SYSTEM_ERROR = "9999"; public static Object ok() { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", 0); obj.put("errmsg", "成功"); return obj; } public static Object ok(Object data) { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", 0); obj.put("errmsg", "成功"); obj.put("data", data); return obj; } public static Object fail() { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", -1); obj.put("errmsg", "错误"); return obj; } public static Object fail(int errno, String errmsg) { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", errno); obj.put("errmsg", errmsg); return obj; } public static Object response(int errno, String errmsg, Object object) { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", errno); obj.put("errmsg", errmsg); obj.put("data", object); return obj; } public static Object badArgument() { return fail(401, "参数不对"); } public static Object badArgumentValue() { return fail(402, "参数值不对"); } public static Object unlogin() { return fail(501, "请登录"); } public static Object serious() { return fail(502, "系统内部错误"); } public static Object unsupport() { return fail(503, "业务不支持"); } public static Object updatedDateExpired() { return fail(504, "更新数据已经失效"); } public static Object updatedDataFailed() { return fail(505, "更新数据失败"); } public static Object unauthz() { return fail(506, "无操作权限"); } public static Object unbindphone() { return fail(507, "未绑定手机号"); } }
public class TokenInterceptor implements HandlerInterceptor { private Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception arg3) throws Exception { } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView model) throws Exception { } //拦截每个请求 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.setCharacterEncoding("utf-8"); //此处是前台将token和loginId 放到了headers里面,后来来获取并处理 String token = request.getHeader("X-Token"); String userAccount = request.getHeader("X-LoginId"); //token不存在 if(StringUtils.isNotBlank(token) && StringUtils.isNotBlank(userAccount)) { UserInfo user = JWT.unsign(token, UserInfo.class); logger.info("preHandle user:{}", user); //解密token后的loginId与用户传来的loginId不一致,一般都是token过期 if(null != user) { if(StringUtils.equalsIgnoreCase(userAccount, user.getUserAccount())) { return true; } else{ responseMessage(response, response.getWriter(), ResponseUtil.unlogin()); return false; } } else { responseMessage(response, response.getWriter(), ResponseUtil.unlogin()); return false; } } else { responseMessage(response, response.getWriter(), ResponseUtil.unlogin()); return false; } } //请求不通过,返回错误信息给客户端 private void responseMessage(HttpServletResponse response, PrintWriter out, Object responseData) { response.setContentType("application/json; charset=utf-8"); String json = JSONObject.toJSONString(responseData); out.print(json); out.flush(); out.close(); } }
<mvc:interceptors> <mvc:interceptor> <!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller --> <mvc:mapping path="/api/user/**" /> <!-- /register.do 和 /login.do 不需要拦截(这里根据项目具体需求来配置)--> <mvc:exclude-mapping path="/api/mall/mall.do" /> <bean class="com.***.util.TokenInterceptor"></bean> </mvc:interceptor> <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 --> </mvc:interceptors>
import axios from 'axios' import { Dialog, Toast } from 'vant'; import store from '@/store/store' // create an axios instance const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url timeout: 5000 // request timeout }) // request interceptor service.interceptors.request.use( config => { if (!config.headers['X-Token']) { config.headers['X-Token'] = `${window.localStorage.getItem('token') || ''}`; config.headers['X-LoginId'] = `${window.localStorage.getItem('userAccount') || ''}`; store.commit('showLoading'); } return config; }, err => { Promise.reject(err); store.commit('hideLoading') } ) // response interceptor service.interceptors.response.use( response => { const res = response.data store.commit('hideLoading'); if (res.errno === 501) { Toast.fail('请登录'); setTimeout(() => { window.location = '#/login/' }, 1500) return Promise.reject('error1') } else if (res.errno === 507) { Toast.fail('请绑定手机号') setTimeout(() => { window.location = '#/user/bind' }, 1500) return Promise.reject('error507') } else if (res.errno === 502) { Toast.fail('网站内部错误,请联系网站维护人员') return Promise.reject('error2') } if (res.errno === 401) { Toast.fail('参数不对'); return Promise.reject('error3') } if (res.errno === 402) { Toast.fail('参数值不对'); return Promise.reject('error4') } if (res.errno === 1001) { Toast.fail('用户错误'); return Promise.reject('error1001') } if (res.errno === 1005) { Toast.fail('短信发送失败'); return Promise.reject('error1005') } if (res.errno === 1006) { Toast.fail('重复获取验证码'); return Promise.reject('error1006') } if (res.errno === 1007) { Toast.fail('短信验证码错误'); return Promise.reject('error1007') } //匹配这个错误 if (res.errno=== 1008) { Toast.fail("无手机号码"); return Promise.reject('error'+res.errno) } if (res.errno=== 1009) { Toast.fail("用户已绑定手机号码"); return Promise.reject('error'+res.errno) } if (res.errno=== 1010) { Toast.fail("手机号码已被使用"); return Promise.reject('error'+res.errno) } if (res.errno === 9999) { Toast.fail('无法操作,请联系网站维护人员'); return Promise.reject('error1007') } else if (res.errno !== 0) { // 非5xx的错误属于业务错误,留给具体页面处理 return Promise.reject(response) } else { return response } }, error => { // console.log('err' + error)// for debug store.commit('hideLoading') Dialog.alert({ title: '警告', message: '连接超时' }); return Promise.reject(error) }) export default service