Spring Boot整合JWT实现token验证

3 篇文章 0 订阅
1 篇文章 0 订阅

介绍jwt

1、JWT官网: https://jwt.io/
      JWT(Java版)的github地址:https://github.com/jwtk/jjwt
2、什么是jwt
     Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

  1. 用户使用账号密码请求服务器,通过校验后,服务器利用私钥生成token,返回到页面
  2. 当再次请求其他接口的时候,把token放在请求头中传给服务器
  3. 服务器拿到浏览器传过来的token进行验证,验证通过继续执行业务,不通过返回对应的错误信息

3、jwt主要的使用场景
     其实在当前的互联网环境中,安全是一个很重要的部分,身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。
4、jwt的优点

  1. 简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
  2. 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
  3. 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持
  4. 不需要在服务端保存会话信息,特别适用于分布式微服务

5、jwt的结构
      Header 头部(标题包含了令牌的元数据,并且包含签名和/或加密算法的类型)
      Payload 负载 (类似于飞机上承载的物品)
      Signature 签名/签证

Header
JWT的头部承载两部分信息:token类型和采用的加密算法

 map.put("alg", "HS256");//声明加密的算法
 map.put("typ", "JWT");//声明类型

加密算法是单向函数散列算法,常见的有MD5、SHA、HAMC。
MD5(message-digest algorithm 5) (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值
SHA (Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,安全性高于MD5
HMAC (Hash Message Authentication Code),散列消息鉴别码,基于密钥的Hash算法的认证协议。用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。常用于接口签名验证
Payload
载荷就是存放有效信息的地方。
有效信息包含三个部分
1.标准中注册的声明
2.公共的声明
3.私有的声明

标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: 面向的用户(jwt所面向的用户)
aud: 接收jwt的一方
exp: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间)
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

Signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和进行验证,所以需要保护好。

6、下面介绍一下整合
首先在spring boot 项目中pom文件引入依赖

<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
	<groupId>com.auth0</groupId>
	<artifactId>java-jwt</artifactId>
	<version>3.8.0</version>
</dependency>

7、工具类

package com.hxj.mall.util.jwt;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

/**
 * @author hxj
 * @version 1.0.0
 * @date 2019年8月6日 上午11:57:36
 */

public class JwtHelper {

	// 秘钥
	static final String SECRET = "hxj-mall-Token";
	// 签名是有谁生成
	static final String ISSUSER = "HXJMALL";
	// 签名的主题
	static final String SUBJECT = "this is MY-mall token";
	// 签名的观众
	static final String AUDIENCE = "HXJ-APP";

	public String createToken(Integer userId) {
		try {
			Algorithm algorithm = Algorithm.HMAC256(SECRET);
			Map<String, Object> map = new HashMap<String, Object>();
			Date nowDate = new Date();
			// 过期时间:2小时
			Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);
			map.put("alg", "HS256");
			map.put("typ", "JWT");
			String token = JWT.create()
					// 设置头部信息 Header
					.withHeader(map)
					// 设置 载荷 Payload
					.withClaim("userId", userId).withIssuer(ISSUSER).withSubject(SUBJECT).withAudience(AUDIENCE)
					// 生成签名的时间
					.withIssuedAt(nowDate)
					// 签名过期的时间
					.withExpiresAt(expireDate)
					// 签名 Signature
					.sign(algorithm);
			return token;
		} catch (JWTCreationException exception) {
			exception.printStackTrace();
		}
		return null;
	}

	public Integer verifyTokenAndGetUserId(String token) {
		try {
			Algorithm algorithm = Algorithm.HMAC256(SECRET);
			JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUSER).build();
			DecodedJWT jwt = verifier.verify(token);
			Map<String, Claim> claims = jwt.getClaims();
			Claim claim = claims.get("userId");
			return claim.asInt();
		} catch (JWTVerificationException exception) {
				exception.printStackTrace();
		}

		return 0;
	}

	public Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second) {
		if (date == null) {
			date = new Date();
		}

		Calendar cal = new GregorianCalendar();

		cal.setTime(date);
		if (year != 0) {
			cal.add(Calendar.YEAR, year);
		}
		if (month != 0) {
			cal.add(Calendar.MONTH, month);
		}
		if (day != 0) {
			cal.add(Calendar.DATE, day);
		}
		if (hour != 0) {
			cal.add(Calendar.HOUR_OF_DAY, hour);
		}
		if (minute != 0) {
			cal.add(Calendar.MINUTE, minute);
		}
		if (second != 0) {
			cal.add(Calendar.SECOND, second);
		}
		return cal.getTime();
	}
}

接下来就可以去使用了,可以写一个拦截器拦截所有方法请求,加上注解过滤不需要验证的方法
注:
WebMvcConfigurerAdapter 在SpringBoot2.0及Spring 5.0中WebMvcConfigurerAdapter已被废弃
官方推荐:直接实现WebMvcConfigurer

//网上找的一个例子
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");   
    }
    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值