后臺(tái)用的是基于Token 的身份驗(yàn)證——JWT(json web token)
1.maven 配置 在pom.xml 中加入如下代碼
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>2.2.0</version>
</dependency>
2.新建JWT.java文件(此處我是放到com.demo.filter包下)
package com.demo.filter;
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class JWT {
private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";
private static final String EXP = "exp";
private static final String PAYLOAD = "payload";
//加密,傳入一個(gè)對(duì)象和有效期
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;
}
}
//解密,傳入一個(gè)加密后的token字符串和解密后的類(lèi)型
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;
}
}
}
3.登錄時(shí),生成token并傳遞給前臺(tái)(ResponseData 類(lèi)在頁(yè)末貼出;此處不一定要像下面這種寫(xiě)法,關(guān)鍵是要看生成token那里)
//處理登錄
@RequestMapping(value="/login.do", produces = "application/json; charset=utf-8")
public @ResponseBody
ResponseData login(String userName, String password, HttpServletRequest request, HttpServletResponse response) throws Exception{
response.setCharacterEncoding("UTF-8");
request.setCharacterEncoding("UTF-8");
ResponseData responseData = ResponseData.ok();
try{
//先到數(shù)據(jù)庫(kù)驗(yàn)證(這一步根據(jù)自己的代碼邏輯來(lái)實(shí)現(xiàn))
User user = service.findUserByNameAndPassword(userName.trim(),CommUtil.generateMD5Str(password));
if(null != user) {
//給用戶(hù)jwt加密生成token 這里是關(guān)鍵,生成了token 后,怎么給前臺(tái)返回,那可以用你自己的方法;
String token = JWT.sign(user, 60L* 1000L* 30L);
//封裝成對(duì)象返回給客戶(hù)端
responseData.putDataValue("token", token);
responseData.putDataValue("user", user);
}
else{
responseData = ResponseData.customerError();
}
}catch (Exception e){
e.printStackTrace();
}
return responseData;
}
4.寫(xiě)一個(gè)攔截;攔截訪問(wèn)的請(qǐng)求
package com.demo.util;
import com.alibaba.fastjson.JSONObject;
import com.demo.bean.User;
import com.demo.filter.JWT;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
public class TokenInterceptor implements HandlerInterceptor {
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 {
}
//攔截每個(gè)請(qǐng)求
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
response.setCharacterEncoding("utf-8");
//此處是前臺(tái)將token和loginId 放到了headers里面,后來(lái)來(lái)獲取并處理
String token = request.getHeader("X-Token");
String loginId = request.getHeader("X-LoginId");
ResponseData responseData = ResponseData.ok();
//token不存在
if(null != token) {
User user = JWT.unsign(token, User.class);
//解密token后的loginId與用戶(hù)傳來(lái)的loginId不一致,一般都是token過(guò)期
if(null != loginId && null != user) {
if(Integer.parseInt(loginId) == user.getId()) {
return true;
}
else{
responseData = ResponseData.forbidden();
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
else
{
responseData = ResponseData.forbidden();
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
else
{
responseData = ResponseData.forbidden();
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
//請(qǐng)求不通過(guò),返回錯(cuò)誤信息給客戶(hù)端
private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseData responseData) {
responseData = ResponseData.forbidden();
response.setContentType("application/json; charset=utf-8");
String json = JSONObject.toJSONString(responseData);
out.print(json);
out.flush();
out.close();
}
}
5.spring-mvc.xml中配置攔截
<mvc:interceptors>
<mvc:interceptor>
<!-- 匹配的是url路徑, 如果不配置或/**,將攔截所有的Controller -->
<mvc:mapping path="/**" />
<!-- /register.do 和 /login.do 不需要攔截(這里根據(jù)項(xiàng)目具體需求來(lái)配置)-->
<mvc:exclude-mapping path="/register.do" />
<mvc:exclude-mapping path="/login.do" />
<bean class="com.demo.util.TokenInterceptor"></bean>
</mvc:interceptor>
<!-- 當(dāng)設(shè)置多個(gè)攔截器時(shí),先按順序調(diào)用preHandle方法,然后逆序調(diào)用每個(gè)攔截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
6.后臺(tái)攔截已經(jīng)做完,接下來(lái)是前端vue+axios 配置了
在main.js中對(duì)axios進(jìn)行配置
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.axios = axios
// 請(qǐng)求時(shí)的攔截
axios.interceptors.request.use(function (config) {
// 發(fā)送請(qǐng)求之前做一些處理
//在登錄的時(shí)候,后臺(tái)會(huì)將token和loginId傳遞過(guò)來(lái),拿到值以后,用localStorage.setItem("jwt",JSON.stringify(data));存起來(lái)
let storageData = localStorage.getItem("jwt");
if(storageData){
storageData = JSON.parse(storageData);
let token = storageData.token,
loginId = storageData.loginId;
config.headers['X-Token'] = token;
config.headers['X-LoginId'] = loginId;
}
return config;
}, function (error) {
// 當(dāng)請(qǐng)求異常時(shí)做一些處理
return Promise.reject(error);
});
// 響應(yīng)時(shí)攔截
axios.interceptors.response.use(function (response) {
// 返回響應(yīng)時(shí)做一些處理
console.log("返回的數(shù)據(jù)",response);
return response;
}, function (error) {
// 當(dāng)響應(yīng)異常時(shí)做一些處理
return Promise.reject(error);
});
7.附上ResponseData 代碼
package com.demo.util;
import java.util.HashMap;
import java.util.Map;
public class ResponseData {
private final String message;
private final int code;
private final Map<String, Object> data = new HashMap<String, Object>();
public String getMessage() {
return message;
}
public int getCode() {
return code;
}
public Map<String, Object> getData() {
return data;
}
public ResponseData putDataValue(String key, Object value) {
data.put(key, value);
return this;
}
private ResponseData(int code, String message) {
this.code = code;
this.message = message;
}
public static ResponseData ok() {
return new ResponseData(200, "Ok");
}
public static ResponseData notFound() {
return new ResponseData(404, "Not Found");
}
public static ResponseData badRequest() {
return new ResponseData(400, "Bad Request");
}
public static ResponseData forbidden() {
return new ResponseData(403, "Forbidden");
}
public static ResponseData unauthorized() {
return new ResponseData(401, "unauthorized");
}
public static ResponseData serverInternalError() {
return new ResponseData(500, "Server Internal Error");
}
public static ResponseData customerError() {
return new ResponseData(1001, "customer Error");
}
}