jwt以及如何使用jwt实现登录
jwt的使用和使用jwt进行登录
什么是jwt
jwt是 JSON WEB TOKEN英文的缩写,它是一个开放标准,它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全传输信息。该信息可以被验证和信任,因为它是数字签名用的。
使用jwt最多的场景就是登陆,一旦用户登陆,那么后续的每个请求都应该包含jwt。
jwt的组成
jwt由三部分组成,每一部分之间用符号"."进行分割,整体可以看做是一个长字符串。
一个经典的jwt的样子:
xxx.xxx.xxx
jwt的三部分分别是:
Header 头部
头部由两部分组成:第一部分是声明类型,在jwt中声明类型就jwt,第二部分是声明加密的算法,加密算法通常使用HMAC SHA256
一个经典的头部:
{
'typ': 'JWT', // 'typ':'声明类型'
'alg': 'HS256' // 'alg':'声明的加密算法'
}
Payload 载体、载荷
这一部分是jwt的主体部分,这一部分也是json对象,可以包含需要传递的数据,其中jwt指定了七个默认的字段选择,这七个字段是推荐但是不强制使用的:
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于识别该JWt除了上述的七个默认字段之外,还可以自定义字段,通常我们说JWT用于用户登陆,就可以在这个地方放置用户的id和用户名
下面这个json对象是一个jwt的Payload部分
{ "sub": "1234567890", "nickname": "leileilei", "id": "1234123" }
- 这里注意虽然可以放自定的信息,但是不要存放一些敏感信息,除非是加密过的,因为这里的信息可能会被截获
signature 签证
这部分是对前两部分进行base64编码在进行加密,这个加密的方式使用的是jwt的头部声明中的加密方式,在加上一个密码(secret)组成的,secret通常是一个随机的字符串,这个secret是服务器特有的,不能够让其他人知道。这部分的组成公式是:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
为什么选择jwt
session的缺点
- 首先在我的认知里jwt用处最多的就是作为用户登陆的凭证,以往这个凭证是使用session和cookie进行存储的,session技术的存储在服务器端的一种技术,构造一个类似于哈希表存储用户id和用户的一些信息,将这个用户id放在cookie里返回给用户,用户每次登陆的时候带上这个cookie,在哈希表中如果可以查到信息,那么说明用户登陆并且得到对应用户的信息。
- 但是session存放在服务器端,当用户量很大时,占用了服务器过多的宝贵的内存资源。同时因为如果有多台服务器,那么当用户登陆时访问了服务器A,那么就只有服务器A上会存储这个用户的信息,当用户访问其他页面时,也许请求会发给服务器B,这时服务器B中是没有用户的信息的,会判定用户处于非登录的状态。也就是说session无法很好的在微服务的架构之中使用。
- 因为session是和cookie结合使用的,如果cookie被截获,那么就会存在安全危机。
jwt的优点
- json形式,而json非常通用性可以让它在很多地方使用
- jwt所占字节很小,便于传输信息
- 需要服务器保存信息,易于扩展
一个jwt的工具类
如果需要使用jwt可以直接拿去使用
package com.lei.commonutils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author leileilei
* @since 2019/10/16
*/
public class JwtUtils {
//常量
public static final long EXPIRE = 1000 * 60 * 60 * 24; //token过期时间
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO"; //秘钥,加盐
// @param id 当前用户ID
// @param issuer 该JWT的签发者,是否使用是可选的
// @param subject 该JWT所面向的用户,是否使用是可选的
// @param ttlMillis 什么时候过期,这里是一个Unix时间戳,是否使用是可选的
// @param audience 接收该JWT的一方,是否使用是可选的
//生成token字符串的方法
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT") //头部信息
.setHeaderParam("alg", "HS256") //头部信息
//下面这部分是payload部分
// 设置默认标签
.setSubject("leileilei") //设置jwt所面向的用户
.setIssuedAt(new Date()) //设置签证生效的时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) //设置签证失效的时间
//自定义的信息,这里存储id和姓名信息
.claim("id", id) //设置token主体部分 ,存储用户信息
.claim("nickname", nickname)
//下面是第三部分
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
// 生成的字符串就是jwt信息,这个通常要返回出去
return JwtToken;
}
/**
* 判断token是否存在与有效
* 直接判断字符串形式的jwt字符串
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* 因为通常jwt都是在请求头中携带,此方法传入的参数是请求
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");//注意名字必须为token才能获取到jwt
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token字符串获取会员id
* 这个方法也直接从http的请求中获取id的
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
将jwt和登录进行结合
controller层
//实现前端登录
@PostMapping("login")
public R login(@RequestBody UcenterMember ucenterMember){
//ucenterMember封装了手机号和密码
//在service里面进行验证
//并且需要返回token,作为单点登录的凭证
String token = ucenterMemberService.login(ucenterMember);
return R.ok().data("token",token);
}
service层
//判断登录
@Override
public String login(UcenterMember ucenterMember) {
//首先获取到正在进行登录的手机和密码
String mobile = ucenterMember.getMobile();
String password = ucenterMember.getPassword();
//判断手机号和密码是否是空值
if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)){
throw new DiyException(20001,"用户名或者密码为空");
}
//判断是否存在这个用户
QueryWrapper<UcenterMember> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile",mobile);
UcenterMember member = baseMapper.selectOne(queryWrapper);
//如果这个member对象是空,那么说明非法访问
if(member == null){
throw new DiyException(20001,"该用户不存在");
}
if(!member.getPassword().equals(MD5.encrypt(password))){
throw new DiyException(20001,"用户名或者密码错误");
}
//走到这里说明登录是成功的
//生成token,使用封装好的工具类
//将该用户的id和用户名放入到token中
String token = JwtUtils.getJwtToken(member.getId(), member.getNickname());
return token;
}
当存在某些需求,需要用户登录之后再进行操作可以使用如下代码
//根据课程id进行下单操作
//最后需要返回订单号,通过订单号生成支付的二维码
@GetMapping("toBuy/{courseId}")
public R toBuy(@PathVariable String courseId, HttpServletRequest request){
//通过jwt工具类,在request中获取到用户id
String userId = JwtUtils.getMemberIdByJwtToken(request);
//如果没有登录则无法购买
if(StringUtils.isEmpty(userId)){
return R.error().message("请先登录后在进行操作");
}
//确认为登录状态之后往下进行操作
String orderNo = orderService.toBuyGetOrderNo(courseId,userId);
return R.ok().data("orderNo",orderNo);
}
axios方式将jwt放在header中
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import cookie from 'js-cookie'
// 创建axios实例
const service = axios.create({
baseURL: 'http://localhost:9002', // api的base_url
timeout: 20000 // 请求超时时间
})
//第三步,将cookie中的token放入到header(请求头)中
// http request 拦截器
service.interceptors.request.use(
config => {
//debugger
if (cookie.get('token')) {
config.headers['token'] = cookie.get('token');
}
return config
},
err => {
return Promise.reject(err);
})
前端的js代码
//实现登录
//第一步调用接口实现登录
submitLogin(){
loginApi.login(this.user)
.then(response => {
//第二步,获取到token,并将token放入到cookie中
cookie.set('token',response.data.data.token,{domain: 'localhost'})
//第四步,请求接口获得用户数据
loginApi.getInfoByToken()
.then(response => {
this.loginInfo = response.data.data.userInfo
//获取返回用户信息,放到cookie里面
cookie.set('ucenter',this.loginInfo,{domain: 'localhost'})
//跳转页面
window.location.href = "/";
})
})
},
jwt以及如何使用jwt实现登录的更多相关文章
- drf框架中jwt认证,以及自定义jwt认证
0909自我总结 drf框架中jwt 一.模块的安装 官方:http://getblimp.github.io/django-rest-framework-jwt/ 他是个第三方的开源项目 安装:pi ...
- Django基于JWT实现微信小程序的登录和鉴权
什么是JWT? JWT,全称Json Web Token,用于作为JSON对象在各方之间安全地传输信息.该信息可以被验证和信任,因为它是数字签名的. 与Session的区别 一.Session是在服务 ...
- Spring Boot + Security + JWT 实现Token验证+多Provider——登录系统
首先呢就是需求: 1.账号.密码进行第一次登录,获得token,之后的每次请求都在请求头里加上这个token就不用带账号.密码或是session了. 2.用户有两种类型,具体表现在数据库中存用户信息时 ...
- koa2+redis+jwt token验证,简单注册登录
首先新建文件夹命名koa-server,npm init,相关包的安装就不说了,这是我的package.json 新建index.js文件,编码如下,config全局配置不用管,redis是一个简单的 ...
- 实战!spring Boot security+JWT 前后端分离架构认证登录!
大家好,我是不才陈某~ 认证.授权是实战项目中必不可少的部分,而Spring Security则将作为首选安全组件,因此陈某新开了 <Spring Security 进阶> 这个专栏,写一 ...
- [JWT] AngularJS Authentication with JWT
Set up server for JWT Authentication 1. require express 2. require faker: If faker is not install ye ...
- asp.net core-14.JWT认证授权 生成 JWT Token
源码下载 语言组织能力不好 ,看这个 视频 用visual studio code打开文件,运行dotnet watch run 之后在postman里面去访问 拿到Token后
- 看图理解JWT如何用于单点登录
单点登录是我比较喜欢的一个技术解决方案,一方面他能够提高产品使用的便利性,另一方面他分离了各个应用都需要的登录服务,对性能以及工作量都有好处.自从上次研究过JWT如何应用于会话管理,加之以前的项目中也 ...
- JWT 多网站单点登录,放弃session
多个网站之间的登录信息共享, 基于cookie - session的登录认证方式跨域等比较复杂.采用基于算法的认证方式, JWT(json web token)的方式. --------------- ...
随机推荐
- Entity Framework中Remove、Modified实体时,在修改或删除时引发主键冲突的问题
问题: try { string fileId = context.NewsT.Where(t => t.Id == Model.Id).FirstOrDefault().FileId; str ...
- 实战交付一套dubbo微服务到k8s集群(3)之二进制安装Maven
maven官网:https://maven.apache.org/ maven二进制下载连接:https://archive.apache.org/dist/maven/maven-3/3.6.1/b ...
- 关于TCP状态TIME_WAIT的理解
1.TIME_WAIT的作用: TIME_WAIT状态存在的理由:1)可靠地实现TCP全双工连接的终止 在进行关闭连接四次挥手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器 ...
- 7A - Kalevitch and Chess
A. Kalevitch and Chess time limit per test 2 seconds memory limit per test 64 megabytes input standa ...
- Linux 驱动框架---net驱动框架
这一篇主要是学习网络设备驱动框架性的东西具体的实例分析可以参考Linux 驱动框架---dm9000分析 .Linux 对于网络设备的驱动的定义分了四层分别是网络接口层对上是IP,ARP等网络协议,因 ...
- Pure CSS Progress Chart
Pure CSS Progress Chart CSS Progress Circle SCSS .example { text-align: center; padding: 4em; } .pie ...
- Flutter 使用Tabbar不要Title
原文 Demo 1 import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp ext ...
- DeFi下半场,除了YFI,还有BGV!
自今年夏季开始,DeFi市场便已经进入火热态势,且持续至今.其中,去中心化交易所(DEX)以及各种金融衍生品的出现,吸引了大批资金的进入,资本市场的目光已从传统金融移到了DeFi市场,期望着能够从De ...
- 系统错误,MSVCP100D.dll找不到或丢失!
文章首发 | 公众号:lunvey 今日研究c++,找了一些示例程序,发现无法打开.弹出如下的报错提示: 作为新时代人类,遇见问题第一件事情就是问度娘.然而眼花缭乱的检索数据,大家众说纷纭,不知道如何 ...
- 用Python实现一个“百度翻译”
import requests import json s = input("请输入你要翻译的内容:") headers = {"User-Agent":&qu ...