Java Token登录验证 使用jjwt生成和解析JWT

Java jjwt生成和解析Token

    • 参考
    • 依赖
    • 流程
    • 生成和解析Jwt
      • 生成jwt
      • 解析Jwt
    • 实例
      • 后端
      • 前端

刚学会了点使用Jwt来验证登录,记录下来

参考

JSON Web Tokens官网 Libraries里有各种语言的推荐包
jjwt的Github网址 JWT官网里面star最多的,所以用了
jjwt官方 生成和解析的例子
前后端分离之JWT用户认证 对JWT有详细的介绍
Java安全验证之JWT实践

依赖

Java Token登录验证 使用jjwt生成和解析JWT_第1张图片
当时在maven仓库里找到的最新版 网盘
Maven仓库 可以自己找最新的

流程

  1. 登录成功后,在Java中生成Jwt,存入数据库,然后返回给前端;前端接收到Jwt,储存起来(cookie或localStorage)。
  2. 前端调用api时放在Header的Authorization里面,后端通过过滤器Filter判断是否已登录。

没有使用框架,单纯的Html、servlet、数据库

生成和解析Jwt

其实就是官方的 然后用谷歌翻译了一波

生成jwt

//构建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

//验证和读取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;
			}
			// 相对应的操作
		}
	});
});

你可能感兴趣的:(后端)