JSON Web Tokens官网 Libraries里有各种语言的推荐包
jjwt的Github网址 JWT官网里面star最多的,所以用了
jjwt官方 生成和解析的例子
前后端分离之JWT用户认证 对JWT有详细的介绍
Java安全验证之JWT实践
当时在maven仓库里找到的最新版 网盘
Maven仓库 可以自己找最新的
没有使用框架,单纯的Html、servlet、数据库
其实就是官方的 然后用谷歌翻译了一波
//构建JWT的示例方法
private String createJWT(String id, String issuer, String subject, long ttlMillis) {
//我们将用于签署令牌的JWT签名算法
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//创建时间
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//我们将使用我们的Api Key秘密签署您的JWT
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(apiKey.getSecret());
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//让我们设置JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now)
.setSubject(subject)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey);
//builder.claim("name", "value"); //设置自定义的信息
//如果已经指定,让我们添加到期日
//过期时间
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
//构建JWT并将其序列化为紧凑的URL安全字符串
return builder.compact();
}
//验证和读取JWT的示例方法
private void parseJWT(String jwt) {
//如果它不是签名的JWS(如预期的那样),则该行将抛出异常
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret()))
.parseClaimsJws(jwt).getBody();
System.out.println("ID: " + claims.getId());
System.out.println("Subject: " + claims.getSubject());
System.out.println("Issuer: " + claims.getIssuer());
System.out.println("Expiration: " + claims.getExpiration());
//claims.get("name") //获取自定义的信息
}
JwtUtil 工具类
package com.util;
import java.security.Key;
import java.util.Date;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class JwtUtil {
// token秘钥 太短会报错
public static String SECRET = "qwerasdfdxzvdfajjlkjeiojznvxndjkfaowijeiodl";
/**
* 生成Jwt的方法
*
* @param id
* 用户ID
* @param subject
* 用户昵称
* @param ttlMillis
* 过期时间
* @return Token String 凭证
*/
public static String createJWT(String id, String subject, long ttlMillis) {
// 签名方法 HS256
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 生成Jwt的时间
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
// 生成秘钥
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
// 设置JWT所存储的信息
JwtBuilder builder = Jwts.builder().setId(id).setIssuedAt(now).setSubject(subject).signWith(signingKey,
signatureAlgorithm);
//builder.claim("name", "value"); //存储自定义信息
// 设置过期时间
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
// 构建JWT并将其序列化为紧凑的URL安全字符串
return builder.compact();
}
/**
* 解析Jwt字符串
*
* @param jwt
* Jwt字符串
* @return Claims 解析后的对象
*/
public static Claims parseJWT(String jwt) {
return Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(SECRET)).parseClaimsJws(jwt).getBody();
}
/**
* 验证JWT
*
* @param jwtStr jwt字符串
* @return JOSNObject 解析结果
* Success 成功标识
* true:成功
* false:失败
* Claim 声明对象
* ErrCode 错误码
* 1005:过期
* 1004:未登录
*/
public static JSONObject validateJWT(String jwtStr) {
JSONObject pojo = new JSONObject();
Claims claims = null;
try {
claims = parseJWT(jwtStr);
pojo.put("Success", true);
pojo.put("Claims", claims);
} catch (ExpiredJwtException e) {
pojo.put("Success", false);
pojo.put("ErrCode", 1005);
e.printStackTrace();
} catch (Exception e) {
pojo.put("Success", false);
pojo.put("ErrCode", 1004);
e.printStackTrace();
}
return pojo;
}
}
LoginServlet 登录
package com.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.util.JwtUtil;
@WebServlet("/user/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 账号
String Account = request.getParameter("Account");
// 密码
String password = request.getParameter("password");
// 登录操作
// 登录成功:
// 有效时间:一天
long ttlMillis = 24 * 60 * 60 * 1000;
// 昵称
String nickname = "star";
// 生成jws
String jws = JwtUtil.createJWT(Account, nickname, ttlMillis);
// jws存到数据库
// 返回给前端
out.print(jws);
out.flush();
out.close();
}
}
JwtFilter 过滤器
package com.filter;
import java.io.IOException;
import java.io.PrintWriter;
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 com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.entity.Result;
import com.util.JwtUtil;
import io.jsonwebtoken.Claims;
// 登录、注册等操作不过滤 拦截servlet下的所有接口
@WebFilter(filterName = "JWTFilter", urlPatterns = { "/servlet/*" })
public class JWTFilter implements Filter {
@Override
public void destroy() {
/* 销毁时调用 */
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
/* 过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理 */
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// jws设置在Header的Authorization里面
String tokenStr = request.getHeader("Authorization");
// 错误说明
String msg = "系统异常";
// 成功标识
boolean flag = false;
// 错误码
int RtnValue = 9099;
// 存放结果的实体类 有属性:success、errNum、message
Result lr = null;
// 用户未登录
if (tokenStr == null || tokenStr.equals("")) {
RtnValue = 1004;
msg = "未登录";
lr = new Result(RtnValue, flag, msg);
out.print(JSON.toJSONString(lr));
out.flush();
out.close();
return;
}
// 解析jws
JSONObject pojo = JwtUtil.validateJWT(tokenStr);
if (pojo.getBooleanValue("Success")) { // 解析成功
Claims claims = (Claims) pojo.get("Claims");
String Account = claims.getId();
// 与数据库里的比较
// true
chain.doFilter(request, response);
// false
/*
* RtnValue = 1004;
* msg = "登录失效";
* lr = new Result(RtnValue, flag, msg);
* out.print(JSON.toJSONString(lr));
* out.flush();
* out.close();
*/
} else { // 解析失败
RtnValue = pojo.getIntValue("ErrCode");
switch (RtnValue) {
case 1005:
msg = "签名过期";
break;
case 1004:
msg = "未登录";
break;
default:
break;
}
lr = new Result(RtnValue, flag, msg);
out.print(JSON.toJSONString(lr));
out.flush();
out.close();
}
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
登录成功后,把获取到的Token存起来
function login() {
var account = $('#account').val();
var password = $('password').val();
$.ajax({
url: 'user/login',
data: {
'account': account,
'password': password
},
dataType: 'json',
success: function (result) {
if (result.success) {
//登录成功 把Token令牌存起来
window.localStorage.setItem('token', result.message);
} else {
alert(result.message);
}
}
});
};
调用api
$(function () {
$.ajax({
headers: {
// 不设置的话,返回信息会出现中文乱码
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
// 传给后端判断是否登录
Authorization: localStorage.getItem('token')
},
url: 'servlet/getUserinfo',
data: {
'id': '1'
},
dataType: 'json',
success: function(result) {
if (result.hasOwnProperty('success')) { // 调用接口被拦截了 登录出错
alert(result.message);
return;
}
// 相对应的操作
}
});
});