package com.filter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.minidev.json.JSONObject;
import com.jwt.Jwt;
import com.jwt.TokenState;
/**
* toekn校验过滤器,所有的API接口请求都要经过该过滤器(除了登陆接口)
* @author running@vip.163.com
*
*/
@WebFilter(urlPatterns="/servlet/*")
public class Filter1_CheckToken implements Filter {
@Override
public void doFilter(ServletRequest argo, ServletResponse arg1,FilterChain chain ) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) argo;
HttpServletResponse response=(HttpServletResponse) arg1;
// response.setHeader("Access-Control-Allow-Origin", "*");
if(request.getRequestURI().endsWith("/servlet/login")){
//登陆接口不校验token,直接放行
chain.doFilter(request, response);
return;
}
//其他API接口一律校验token
System.out.println("开始校验token");
//从请求头中获取token
String token=request.getHeader("token");
Map<String, Object> resultMap=Jwt.validToken(token);
TokenState state=TokenState.getTokenState((String)resultMap.get("state"));
switch (state) {
case VALID:
//取出payload中数据,放入到request作用域中
request.setAttribute("data", resultMap.get("data"));
//放行
chain.doFilter(request, response);
break;
case EXPIRED:
case INVALID:
System.out.println("无效token");
//token过期或者无效,则输出错误信息返回给ajax
JSONObject outputMSg=new JSONObject();
outputMSg.put("success", false);
outputMSg.put("msg", "您的token不合法或者过期了,请重新登陆");
output(outputMSg.toJSONString(), response);
break;
}
}
public void output(String jsonStr,HttpServletResponse response) throws IOException{
response.setContentType("text/html;charset=UTF-8;");
PrintWriter out = response.getWriter();
// out.println();
out.write(jsonStr);
out.flush();
out.close();
}
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("token过滤器初始化了");
}
@Override
public void destroy() {
}
}
package com.jwt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import net.minidev.json.JSONObject;
public class Jwt {
/**
* 秘钥
*/
private static final byte[] SECRET="3d990d2276917dfac04467df11fff26d".getBytes();
/**
* 初始化head部分的数据为
* {
* "alg":"HS256",
* "type":"JWT"
* }
*/
private static final JWSHeader header=new JWSHeader(JWSAlgorithm.HS256, JOSEObjectType.JWT, null, null, null, null, null, null, null, null, null, null, null);
/**
* 生成token,该方法只在用户登录成功后调用
*
* @param Map集合,可以存储用户id,token生成时间,token过期时间等自定义字段
* @return token字符串,若失败则返回null
*/
public static String createToken(Map<String, Object> payload) {
String tokenString=null;
// 创建一个 JWS object
JWSObject jwsObject = new JWSObject(header, new Payload(new JSONObject(payload)));
try {
// 将jwsObject 进行HMAC签名
jwsObject.sign(new MACSigner(SECRET));
tokenString=jwsObject.serialize();
} catch (JOSEException e) {
System.err.println("签名失败:" + e.getMessage());
e.printStackTrace();
}
return tokenString;
}
/**
* 校验token是否合法,返回Map集合,集合中主要包含 state状态码 data鉴权成功后从token中提取的数据
* 该方法在过滤器中调用,每次请求API时都校验
* @param token
* @return Map<String, Object>
*/
public static Map<String, Object> validToken(String token) {
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
JWSObject jwsObject = JWSObject.parse(token);
Payload payload = jwsObject.getPayload();
JWSVerifier verifier = new MACVerifier(SECRET);
if (jwsObject.verify(verifier)) {
JSONObject jsonOBj = payload.toJSONObject();
// token校验成功(此时没有校验是否过期)
resultMap.put("state", TokenState.VALID.toString());
// 若payload包含ext字段,则校验是否过期
if (jsonOBj.containsKey("ext")) {
long extTime = Long.valueOf(jsonOBj.get("ext").toString());
long curTime = new Date().getTime();
// 过期了
if (curTime > extTime) {
resultMap.clear();
resultMap.put("state", TokenState.EXPIRED.toString());
}
}
resultMap.put("data", jsonOBj);
} else {
// 校验失败
resultMap.put("state", TokenState.INVALID.toString());
}
} catch (Exception e) {
//e.printStackTrace();
// token格式不合法导致的异常
resultMap.clear();
resultMap.put("state", TokenState.INVALID.toString());
}
return resultMap;
}
}
package com.jwt;
/**
* 枚举,定义token的三种状态
* @author running@vip.163.com
*
*/
public enum TokenState {
/**
* 过期
*/
EXPIRED("EXPIRED"),
/**
* 无效(token不合法)
*/
INVALID("INVALID"),
/**
* 有效的
*/
VALID("VALID");
private String state;
private TokenState(String state) {
this.state = state;
}
/**
* 根据状态字符串获取token状态枚举对象
* @param tokenState
* @return
*/
public static TokenState getTokenState(String tokenState){
TokenState[] states=TokenState.values();
TokenState ts=null;
for (TokenState state : states) {
if(state.toString().equals(tokenState)){
ts=state;
break;
}
}
return ts;
}
public String toString() {
return this.state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
package com.jwt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
/**
* 单元测试(请自行引入junit4 Jar包)
* @author running@vip.163.com
*
*/
public class JwtTestCase {
@Test
@SuppressWarnings("unchecked")
public void test1() {
// 正常生成token----------------------------------------------------------------------------------------------------
String token = null;
Map<String, Object> payload = new HashMap<String, Object>();
Date date = new Date();
payload.put("uid", "291969452");// 用户id
payload.put("iat", date.getTime());// 生成时间:当前
payload.put("ext", date.getTime() + 2000 * 60 * 60);// 过期时间2小时
token = Jwt.createToken(payload);
System.out.println("新生成的token是:" + token+"\n马上将该token进行校验");
Map<String, Object> resultMap = Jwt.validToken(token);
System.out.println("校验结果是:" + getResult((String)resultMap.get("state")) );
HashMap<String,String> dataobj = (HashMap<String,String>) resultMap.get("data");
System.out.println("从token中取出的payload数据是:" +dataobj.toString());
}
public void test2() {
// 校验过期----------------------------------------------------------------------------------------------------
String token = null;
Map<String, Object> payload = new HashMap<String, Object>();
Date date = new Date();
payload.put("uid", "291969452");// 用户id
payload.put("iat", date.getTime());// 生成时间
payload.put("ext", date.getTime());// 过期时间就是当前
token = Jwt.createToken(payload);
System.out.println("新生成的token是:" + token+"\n马上将该token进行校验");
Map<String, Object> resultMap = Jwt.validToken(token);
System.out.println("校验结果是:" + getResult((String)resultMap.get("state")) );
}
@SuppressWarnings("unchecked")
public void test2_1() {
// 不校验过期(当payload中无过期ext字段时)----------------------------------------------------------------------------------------------------
String token = null;
Map<String, Object> payload = new HashMap<String, Object>();
Date date = new Date();
payload.put("uid", "291969452");// 用户id
payload.put("iat", date.getTime());// 生成时间
token = Jwt.createToken(payload);
System.out.println("新生成的token是:" + token+"\n马上将该token进行校验");
Map<String, Object> resultMap = Jwt.validToken(token);
System.out.println("校验结果是:" + getResult((String)resultMap.get("state")) );
HashMap<String,String> dataobj = (HashMap<String,String>) resultMap.get("data");
System.out.println("从token中取出的payload数据是:" +dataobj.toString());
}
public void test3() {
// 校验非法token的情况----------------------------------------------------------------------------------------------------
String token = null;
Map<String, Object> payload = new HashMap<String, Object>();
Date date = new Date();
payload.put("uid", "291969452");// 用户id
payload.put("iat", date.getTime());// 生成时间
payload.put("ext", date.getTime());// 过期时间就是当前
token = Jwt.createToken(payload);
System.out.println("新生成的token是:" + token);
System.out.println("将新生成的token加点调料再来进行校验");
token = token + "YouAreSB";
Map<String, Object> resultMap = Jwt.validToken(token);
System.out.println("校验结果是:" + getResult((String)resultMap.get("state")) );
System.out.println("原因是(非法token,payload参数可能经过中间人篡改,或者别人伪造的token)" );
}
public void test4() {
// 校验异常的情况----------------------------------------------------------------------------------------------------
String token = "123";
System.out.println("我胡乱传一个token:" + token);
Map<String, Object> resultMap = Jwt.validToken(token);
System.out.println("校验结果是:" + getResult((String)resultMap.get("state")) );
System.out.println("原因是(token格式不合法导致的程序异常)");
}
public String getResult(String state) {
switch (TokenState.getTokenState(state)) {
case VALID:
//To do somethings
state = "有效token";
break;
case EXPIRED:
state = "过期token";
break;
case INVALID:
state = "无效的token";
break;
}
return state;
}
}