Jwt简单使用

在分布式项目中,经常需要处理session共享的问题,解决的方式有很多,比如采用session或者cookie,或者redis进行存储都是解决方案,今天给大家介绍另一种比较轻量级的解决方式,就是使用jwt生成token,服务端进行加解密来处理;

首先要了解一下jwt的三个基本术语,

Header

Header是由以下这个格式的Json通过Base64编码(编码不是加密,是可以通过反编码的方式获取到这个原来的Json,所以JWT中存放的一般是不敏感的信息)生成的字符串,Header中存放的内容是说明编码对象是一个JWT以及使用“SHA-256”的算法进行加密(加密用于生成Signature)

{
“typ”:“JWT”,
“alg”:“HS256”
}

Claim

Claim是一个Json,Claim中存放的内容是JWT自身的标准属性,所有的标准属性都是可选的,可以自行添加,比如:JWT的签发者、JWT的接收者、JWT的持续时间等;同时Claim中也可以存放一些自定义的属性,这个自定义的属性就是在用户认证中用于标明用户身份的一个属性,比如用户存放在数据库中的id,为了安全起见,一般不会将用户名及密码这类敏感的信息存放在Claim中。将Claim通过Base64转码之后生成的一串字符串称作Payload。

{
“iss”:“Issuer —— 用于说明该JWT是由谁签发的”,
“sub”:“Subject —— 用于说明该JWT面向的对象”,
“aud”:“Audience —— 用于说明该JWT发送给的用户”,
“exp”:“Expiration Time —— 数字类型,说明该JWT过期的时间”,
“nbf”:“Not Before —— 数字类型,说明在该时间之前JWT不能被接受与处理”,
“iat”:“Issued At —— 数字类型,说明该JWT何时被签发”,
“jti”:“JWT ID —— 说明标明JWT的唯一ID”,
“user-definde1”:“自定义属性举例”,
“user-definde2”:“自定义属性举例”
}

Signature

Signature是由Header和Payload组合而成,将Header和Claim这两个Json分别使用Base64方式进行编码,生成字符串Header和Payload,然后将Header和Payload以Header.Payload的格式组合在一起形成一个字符串,然后使用上面定义好的加密算法和一个密匙(这个密匙存放在服务器上,用于进行验证)对这个字符串进行加密,形成一个新的字符串,这个字符串就是Signature。

在这里插入图片描述

JWT实现认证的原理

服务器在生成一个JWT之后会将这个JWT会以Authorization : Bearer JWT 键值对的形式存放在cookies里面发送到客户端机器,在客户端再次访问收到JWT保护的资源URL链接的时候,服务器会获取到cookies中存放的JWT信息,首先将Header进行反编码获取到加密的算法,在通过存放在服务器上的密匙对Header.Payload 这个字符串进行加密,比对JWT中的Signature和实际加密出来的结果是否一致,如果一致那么说明该JWT是合法有效的,认证成功,否则认证失败。

在这里插入图片描述

下面通过两个工具类来说明一下JWT的具体使用,首先需要导入jwt的jar包,

<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.1</version>
</dependency>
/**
 * jwt工具类封装
 * @author asus
 *
 */
public class JwtUtils {
	
	public static final String SUBJECT = "congge";
	
	/**
	 * 设置token的过期时间
	 */
	public static final long EXPIRITION = 1000 * 24 * 60 * 60 * 7;
	
	/**
	 * 秘钥,不同的环境应该配置不同的秘钥,注意保存好,不要泄露
	 */
	public static final String APPSECRET_KEY = "congge_secret";
	
	/**
	 * 加密生成token
	 * @param user
	 * @return
	 */
	public static String generateJsonWebToken(Users user){
		
		if(user.getId() == null || user.getUsername()==null||user.getFaceImage()==null){
			return null;
		}
		
		String token = Jwts.builder().setSubject(SUBJECT)
			.claim("id", user.getId())
			.claim("name",user.getUsername())
			.claim("img", user.getFaceImage())
			.setIssuedAt(new Date())
			.setExpiration(new Date(System.currentTimeMillis() + EXPIRITION ))
			.signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
		return token;
	}
	
	/**
	 * 解密token获取用户信息
	 * @param token
	 * @return
	 */
	public static Claims checkJWT(String token){
		try {
			final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
			return claims;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		
	}
	
	/**
	 * eyJhbGciOiJIUzI1NiJ9.
	 * eyJzdWIiOiJjb25nZ2UiLCJpZCI6IjExMDExIiwibmFtZSI6Im51b3dlaXNpa2kiLCJpbWciOiJ3d3cudW9rby5jb20vMS5wbmciLCJpYXQiOjE1NTQ5OTI1NzksImV4cCI6MTU1NTU5NzM3OX0.
	 * 6DJ9En-UBcTiMRldZeevJq3e1NxJgOWryUyim4_-tEE

	 * @param args
	 */
	
	public static void main(String[] args) {
		
		Users user = new Users();
		user.setId("11011");
		user.setUsername("nuoweisiki");
		user.setFaceImage("www.uoko.com/1.png");
		String token = generateJsonWebToken(user);
		
		System.out.println(token);
		
		System.out.println("解密 ====================");
		
		Claims claims = checkJWT(token);
		if(claims != null){
			String id = claims.get("id").toString();
			String name = claims.get("name").toString();
			String img = claims.get("img").toString();
			
			System.out.println("id:" + id);
			System.out.println("name:" + name);
			System.out.println("img:" + img);
		}
		
	}
	
}

运行一下这段程序,可以看到如下结果,可以看出来,我们加密的用户信息是可以成功解密出来的,利用这个特性,可以将用户一些不敏感的信息通过jwt加解密的方式在客户端和服务端之间进行传递,就算是在分布式环境下,大家用的是同一套代码,加解密规则一样,因此对于同一个用户是可以很方便的进行操作,
在这里插入图片描述

那么实际业务中该如何使用呢?我认为可以存在这一一个场景,用户登录成功后,后端通过jwt产生一个token返回给客户端,客户端进行存储,以后每次访问相关资源时候,后端会有一个拦截器进行拦截,按照定义好的解密规则解密出用户信息,解密成功并且存在,则允许进行后续的操作,下面是一段模拟代码,有兴趣的小伙伴可以参考,


public class JwtInterceptor implements HandlerInterceptor{
	
	/**
	 * 模拟拦截用户请求的url,并从url中读取前端传来的token,如果校验通过,则允许进行后续其他的操作
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		String token = request.getHeader("authorization");
		Claims claims = JwtUtils.checkJWT(token);
		String userId = claims.get("id").toString();
		String userName = claims.get("name").toString();
		String img = claims.get("img").toString();
		UserService userService = SpringContextUtil.getBean("usersService");
		Users user = userService.findById(userId);
		if(user != null){
			return true;
		}else{	
			//生成token的动作是不是应该在用户登录成功的时候产生呢?
			return false;
		}
	}
	
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小码农叔叔

谢谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值