JWT的基础使用

JWT

全称json web token,通过数字签名的方式,以json对象为载体在不同的服务器终端之间的传输信息

使用JWT解决传统session的弊端

HRTTP协议是一个无状态的协议,对于服务器而言,而同一个用户向服务器发出一系列的业务请求,对请求没有处理的话,服务器会任务多个请求来自不同的用户

使用隐藏表单,cookie,session,和url重写后服务器就能够识别我们的一系列请求是否来源一个用户

传统的session认证有如下弊端

1.登录的信息,都会保存在服务器的session中随着用户增加,服务器的开销会明显增大

2.由于session存放在服务器的物理内存中,所以在分布式架构模式下这种方式明显会失效,也可以利用session共享机制,或者利用redis缓存解决

3.非浏览器的客户端:手机移动端是不适用的,因为session是依赖cookie的,移动端是没有cookie的,如果浏览器禁用了cookie,session的方式也会失效

4.基于cookie的cookie无法做到跨域,所有session的认证也无法跨域,对于单点登录不适用

JWT认证流程

前端将用户名和密码发送到后端服务器。后端服务器对用户名和密码验证通过后,将用户信息作为JWT Payload负载,将其与头部进行Base64编号拼接后签名,形成JWT。形成的JWT本质上就是一个形如lll.zzz.xxx的字符串;
后端将JWT字符串作为登陆成功的返回结果返回给客户端。前端可以将返回结果保存在localStorage,退出登陆时,前端删除保存的JWT即可;
前端在每次请求时将JWT放入HTTP Header中的Authorization位;
后端检查是否存在,如果验证JWT有效,后端就可以使用JWT中包含的用户信息。
JWT的组成
JWT其实就是一段字符串,由标头(Header)、有效载荷(Payload)和签名(Signature)这三部分组成,用 . 拼接。在传输的时候,会将JWT的三部分分别进行Base64编码后用.进行连接形成最终传输的字符串。

1.Header
它会使用 Base64编码组成JWT结构的第一部分。

Header{ //标头
‘typ’:’JWT’, 表示token类型
‘alg’:’HS256’ 表示签名算法
}
2.Payload
用于存储主要信息,使用 Base64编码组成JWT结构的第二部分。由于该信息是可以被解析的,所以,在信息中不要存放敏感信息。

Payload //有效负载
{
‘userCode’:’43435’,
‘name’:’john’,
‘phone’:‘13950497865’
}
3.Signature
前面两部分都使用Base64进行编码,前端可以解开知道里面的信息, Signature需要使用编码后的header和payload以及我们提供的一密钥,然后使用header中指定的签名算法进行签名,以保证JWT没有被篡改过。

    使用Signature签名可以防止内容被篡改。如果有人对头部及负载内容解码后进行修改,再进行编码,最后加上之前签名组成新的JWT。那么服务器会判断出新的头部和负载形成的签名和JWT附带的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,得出来的签名也是不一样的。

JWT的使用
1.JWT的环境搭建
在pom.xml文件中导入依赖:

<!--   JWT依赖-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.13.0</version>
</dependency>

<!--        添加web启动器坐标-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.创建JWT工具类Util
JWT的创建

  /**
     * 创建JWT
     * @param map
     * @return
     */
    public String creatJWT(Map<String,String> map){
        //设置Jwt的超时时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE,30);
        //创建JWT,使用JWT.creat()方法进行创建
        //此时builder对象中默认设置了header--表头,默认为JWT
        JWTCreator.Builder builder = JWT.create();
        //将信息写入有效载荷中payload
        for (String key:map.keySet()){
            //通过withClaim方法传入传输到payload中
            builder.withClaim(key,map.get(key));
        }
        //利用builder和签名创健token,同时利用Calender类设置过期时间
        String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256("lovo"));
        return token;
    }

JWT的解码
   /**
     * 通过token和键解码信息
     * @param token
     * @param key
     * @return
     */
    public String verify(String token,String key){
        //创建解码对象,利用JWT签名去完成解码对象的创建
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("lovo")).build();
        //包含了JWT解码信息
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        //利用键得到存放在有效负载payload的数据
        String value = decodedJWT.getClaim(key).asString();
        return value;
    }

工具类测试

 public static void main(String[] args) {
        Util util = new Util();
        Map map = new HashMap();
        map.put("name","tom");
        map.put("pwd","123");
        System.out.println(util.creatJWT(map));
 
        String token = util.creatJWT(map);
        String value = util.verify(token,"pwd");
//        System.out.println(value);
    }

3.书写控制类Controller,用于JWT的发送

@Controller
public class JWTController {
 
 
    /**
     * 模拟登录
     * @param name
     * @param pwd
     * @param response
     * @return
     */
    @RequestMapping("login")
    @ResponseBody
    public String login(String name, String pwd, HttpServletResponse response) {
        if (name.equals("java") && pwd.equals("123")) {
            //此时拥有该用户,则利用该用户的信息创建JWT
            Map map = new HashMap();
            map.put("name", name);
            map.put("pwd", pwd);
            String token = new Util().creatJWT(map);
            //通过响应头发送给客户端
            response.setHeader("token", token);
            return "ok";
        }
        return "no";
    }
 
    @RequestMapping("getLogin")
    @ResponseBody
    public String getLogin(HttpServletRequest request){
        String token = request.getHeader("token");
        //利用工具对其进行解码
        String name = new Util().verify(token,"name");
        String pwd = new Util().verify(token,"pwd");
        return "name="+name+"&pwd="+pwd;
    }
 
}

4.在resource目录下书写user.html,用于JWT的接收
客户端通过axios接收响应头,并保存在sessionStorage中。

客户端会再次请求,读取localStorage的JWT信息,以请求头的方式,发送给服务器。

服务器从请求头中得到jwt字符串,解析后,得到数据。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="axios.min.js"></script>
</head>
<body>
<form action="#">
    用户名:<input type="text" id="name"><br>
    密码:<input type="text" id="pwd"><br>
    <input type="button" value="登录" onclick="login()">
    <input type="button" value="获取登录对象" onclick="getLogin()">
</form>
 
<script>
    function login(){
        let nameObj = document.getElementById("name")
        let pwdObj = document.getElementById("pwd")
        axios.get('/login',{
            params:{
                name:nameObj.value,
                pwd:pwdObj.value
            }
        }).then(res=>{
            console.log(res)
            if (res.data==='ok'){
                localStorage.setItem("token",res.headers.token)
            }else {
                alert("用户名或密码错误!")
            }
        })
    }
 
 
    /**
     * 获取登录对象
     */
    function getLogin(){
        //读取localStorage的信息,以请求头的方式,发送给服务器
        let token = localStorage.getItem("token");
        //添加配置,在请求头中加入JWT的信息
        let config = {
            headers:{"token":token}
        }
        axios.get('/getLogin',config).then(res=>{
            console.log(res)
        })
    }
</script>
 
</body>
</html>

5.MainServer测试

@SpringBootApplication
public class MainServer {
    public static void main(String[] args) {
        SpringApplication.run(MainServer.class,args);
    }
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值