前后端分离的登录

article/2025/10/5 16:50:07

          

目录

          

        一、跨域认证的问题

​编辑 

        1.2 什么是JWT

        1.3 JWT原理

        1.4 JWT结构

        1.4.1 Header

        1.4.2  Payload

        1.4.3  Signature

        1.5 使用JWT---JAVA

               1.5.1 引入依赖

                1.5.2 封装一个JWT工具类  

        二、完成前后端分离的登录功能

        2.1 前端代码

        2.2 配置拦截器axios

        2.3 后台拦截器


        一、跨域认证的问题

        互联网服务离不开用户认证。一般流程是下面这样。

        

        1、用户向服务器发送用户名和密码。

        2、服务器验证通过后,在当前会话(session)里面保存相关数据,比如用户角色、登录时间等等。

        3、服务器向用户返回一个 session_id,写入用户的 Cookie。

        4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

        5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

 

        这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。

 

        1.2 什么是JWT

        JSON Web Token是目前最流行的跨域认证解决方案,,适合前后端分离项目通过Restful API进行数据交互时进行身份认证. --JWT可以帮你生成一串字符串令牌。

        1.3 JWT原理

        JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

        {
          "姓名": "张三",
          "角色": "管理员",
          "到期时间": "2021年7月1日0点0分"
     }

        

        以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名.

        服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

        1.4 JWT结构

                实际的 JWT 大概就像下面这样。

 

        它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

        

        JWT 的三个部分依次如下。

        1.Header(头部) 数据格式是固定2.Payload(载荷) 包含用户信息以及过期时间等---信息3.Signature(签名)加密

        写成一行,就是下面的样子。

        Header.Payload.Signature

 

        下面依次介绍这三个部分。  

        1.4.1 Header

        Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

        

{"alg": "HS256","typ": "JWT"
}

        上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

        最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。

        1.4.2  Payload

                Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

        - iss (issuer):签发人
        - exp (expiration time):过期时间
        - sub (subject):主题
        - aud (audience):受众
        - nbf (Not Before):生效时间
        - iat (Issued At):签发时间
        - jti (JWT ID):编号

                除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。  

        

{"sub": "1234567890","name": "John Doe","admin": true
}

        注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

        这个 JSON 对象也要使用 Base64URL 算法转成字符串。

        1.4.3  Signature

        Signature 部分是对前两部分的签名,防止数据篡改

        首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

        

HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

        算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

        1.5 使用JWT---JAVA

               1.5.1 引入依赖


<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.11.0</version></dependency>

                1.5.2 封装一个JWT工具类  

package com.aaa.qy158springboot02.util;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class JwtUtil {private static final String SIGN="aaa"; //密钥//1.通过jwt生成token字符串。public static String createToken(Map<String,Object> params){Map<String,Object> head=new HashMap<>();head.put("alg","HS256");head.put("typ","JWT");//定义颁发时间Date iss=new Date();//过期时间Calendar nowTime = Calendar.getInstance();nowTime.add(Calendar.MINUTE,30);Date expire = nowTime.getTime();String token = JWT.create()//指定头信息.withHeader(head)//载荷种的过期时间.withExpiresAt(expire)//颁发时间.withIssuedAt(iss)//颁发人.withIssuer("yankeqi")//自定义的载荷内容.withClaim("userInfo",params)//签名.sign(Algorithm.HMAC256(SIGN));return token;}//2. 判断token是否合法public static boolean verifyToken(String token){JWTVerifier build = JWT.require(Algorithm.HMAC256(SIGN)).build();try {DecodedJWT verify = build.verify(token);return true;}catch (Exception e){e.printStackTrace();return false;}}//3. 解析token种的内容public static Map<String,Object> decodeJWT(String token){Map<String, Object> userInfo = JWT.decode(token).getClaim("userInfo").asMap();return userInfo;}public static void main(String[] args) {HashMap<String, Object> map = new HashMap<>();map.put("name","汪鹏");map.put("id",1);map.put("age",19);String token = createToken(map);System.out.println(token);Map<String, Object> map2= decodeJWT(token);System.out.println(map2);//       boolean is=verifyToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySW5mbmPIiwiaWQiOjEsImFnZSI6MTl9LCJpc3MiOiJ5YW5rZXFpIiwiZXhwIjoxNjY5MTcwODA3LCJpYXQiOjE2NjkxNjkwMDd9.3BZh1ylEosSBfn2n3Y6xMKv8Ut9pyxm37Y0-JinJdB0");
//        System.out.println(is);}
}

        二、完成前后端分离的登录功能

        

        2.1 前端代码

<template><div id="login"><div id="loginBox"><el-form :model="loginForm" status-icon :rules="loginRules" ref="ruleForm" label-width="100px" class="demo-ruleForm"><el-form-item label="账号" prop="name"><el-input type="text" v-model="loginForm.name" autocomplete="off"></el-input></el-form-item><el-form-item label="密码" prop="age"><el-input type="text" v-model="loginForm.age" autocomplete="off"></el-input></el-form-item><el-form-item><el-button type="primary" @click="login()">提交</el-button><el-button>重置</el-button></el-form-item></el-form></div></div>
</template><script>export default {name: "Login.vue",data(){return{loginForm:{name:"",age:""},//校验loginRules:{name:[{ required: true, message: '请输入账号', trigger: 'blur' },],age:[{ required: true, message: '请输入密码', trigger: 'blur' },]}}},methods:{login(){this.$http.post("http://localhost:8000/login",this.loginForm).then(resp=>{console.log(resp.data.code)if (resp.data.code===2000){//登录成功 获取服务器相应的token值,保存到localStoragelocalStorage.setItem("token",resp.data.data);//路由跳转  不能使用  location.hrefthis.$router.push("/student")}else {this.$message.error("登陆失败,账号密码错误");}})}}}
</script><style>#loginBox{width: 500px;height: 290PX;margin: 100px auto;}#loginForm{margin:50px auto;}
</style>

        2.2 配置拦截器axios

//设置axios请求的拦截器
axios.interceptors.request.use(config=>{//从localStorage获取令牌信息var token = localStorage.getItem("token");//判断是否获取token 只要token有值 则返回trueif (token){//把token信息放入请求头中config.headers.token=token;}return config;
})

        2.3 后台拦截器

package com.aaa.qy158springboot02.interceptor;import com.aaa.qy158springboot02.util.JwtUtil;
import com.aaa.qy158springboot02.vo.Result;
import com.alibaba.fastjson.JSON;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.setContentType("application/json;charset=utf-8");//1.获取请求头种的tokenString token = request.getHeader("token");//2.判断token是否为nullif(StringUtils.hasText(token)){//校验token是否合法if(JwtUtil.verifyToken(token)){return true;}}PrintWriter writer = response.getWriter();Result result=new Result(4001,"未登录");String jsonString = JSON.toJSONString(result);writer.print(jsonString);writer.flush();writer.close();return false;}
}

http://chatgpt.dhexx.cn/article/qbuHgHjQ.shtml

相关文章

前后端分离架构

原文 参考&#xff1a; 到底什么是前后端分离1 到底什么是前后端分离2 到底什么是前后端分离3 前后端分离是个架构设计问题。所谓架构设计&#xff0c;实际上是如何合理的对现实的人力架构进行系统映射&#xff0c;以便最大限度的提高整个公司的运行效率。 前后端的定义 前后…

前后端分离的跨域问题

跨域问题原因 在现在流行的前后端分离开发中&#xff0c;跨域问题突显了出来&#xff0c;跨域问题的根本原因&#xff1a;浏览器有同源策略限制&#xff0c;当前域名的js只能读取同域下的窗口属性&#xff0c;这是一个基础安全功能。那么什么是同源策略呢&#xff1f;即两资源的…

前后端分离历史

文章目录 前后端分离前后端分离的历史前后端合并前后端耦合前后端“分离”大厂的方案前后端分离的理想方式前后端分离的好处前后端分离的挑战总结 前端历史前端开发的历史和趋势什么是前端前后端不分的时代后端 MVC 的开发模式前端工程师的角色典型的 PHP 模板AjaxWeb 2.0前端 …

小谈什么是前后端分离?

什么是前后端分离&#xff1f; 学习目标 什么是前后端分离&#xff1f;前后端分离初了解为什么要前后端分离&#xff1f;1、前后职责分离2、前后技术分离3、前后分离带来了用户用户体验和业务处理解耦4、前后分离&#xff0c;可以分别归约两端的设计 前后分离架构接口设计 用户…

java 前后端分离_Java项目如何实现前后端分离

Java项目如何实现前后端分离 发布时间:2020-11-20 15:55:52 来源:亿速云 阅读:103 作者:Leah 今天就跟大家聊聊有关Java项目如何实现前后端分离,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 构建springboot…

java 前后端分离

前后端分离的开发模式&#xff0c;这两年确实被炒得如火如荼&#xff0c;导致这个话题也成了面试极其爱问的一个问题&#xff0c;尤其是换工作、跳槽&#xff0c;之前不管你是做后端&#xff0c;还是前端&#xff0c;都可能会涉及。 面试官常问&#xff1a; 诶&#xff1f;你…

前后端ajax分离如何做seo,前后端分离 seo

目录 一、bootstrap 前后端分离 表现层完全由前端掌控是最好的。所以掌握jsp和jstl是挺好的&#xff0c;等你全掌握之后麻利得把页面模板搞定就可以嘲笑后端都是bottleneck了。 当然不愿意用jsp/jstl之类的&#xff0c;也可以考虑完全用ajax。 为什么说前后端分离不利于seo的原…

前后端分离

一、项目有前后端分离和前后端不分离&#xff1a; 在前后端不分离架构中&#xff0c;所有的静态资源和业务代码统一部署在同一台服务器上。服务器接收到浏览器的请求后&#xff0c;进行处理得到数据&#xff0c;然后将数据填充到静态页面中&#xff0c;最终返回给浏览器。 实现…

Spring Security 前后端分离

前后端分离概述 前后端分离指的就是前后端分离部署&#xff0c;前端 调用后端API&#xff0c;后端 返回 JSON格式数据&#xff0c;页面是由前端渲染并展示到浏览器中。 相比较传统的单体项目 &#xff0c;页面是由后端渲染完成后返回给浏览器的。&#xff08;jsp、thymeleaf、…

实现前后端分离

对目前的web来说&#xff0c;前后端分离已经变得越来越流行了&#xff0c;越来越多的企业/网站都开始往这个方向靠拢。那么&#xff0c;为什么要选择前后端分离呢&#xff1f;前后端分离对实际开发有什么好处呢? 为什么选择前后端分离 1. 在以前传统的网站开发中&#xff0c…

何为前后端分离?一文搞懂前后端分离发展史

目录 一、前言 二、前后端分离的演进过程 2.1 发展的三个阶段 2.2 前后端不分离阶段&#xff08;Java的JSP作为前端视图时代&#xff09; 2.3 前后端半分离阶段&#xff08;前后端使用Ajax交互的半分离时代&#xff09; 2.4 前后端完全分离阶段&#xff08;前后端使…

前后端分离架构概述

1、背景 前后端分离已成为互联网项目开发的业界标准使用方式&#xff0c;通过nginxtomcat的方式&#xff08;也可以中间加一个nodejs&#xff09;有效的进行解耦&#xff0c;并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务&#xff08;多种客户…

前后端分离架构,超全面详解~

此文通俗易懂&#xff0c;全面讲解前后端分离架构核心思想与作用&#xff0c;对学习微服务、开发企业项目大有裨益&#xff0c;建议收藏细品&#xff0c;好好领悟&#xff01;~ 一、简介 前后端分离已成为互联网项目开发的业界标准使用方式&#xff0c;通过nginxtomcat的方式&a…

到底什么是前后端分离

1、到底什么是前后端分离&#xff1f; 前后端分离的"前"特指浏览器端(或客户端)&#xff0c;直接呈现给用户的&#xff1b;后端是服务器端&#xff0c;处理业务逻辑和数据&#xff0c;不呈现给用户。 Java服务器端初学者最容易引起误解的一个概念就是&#xff1a;J…

c语言 链表基本操作

对于c语言的单链表来说&#xff0c;应该是数据结构中比较简单的一类结构&#xff0c;我们只要认识链表结构&#xff0c;对指针和结构体掌握好&#xff0c;其实编写代码并不算太难。 链表结构&#xff1a; 对于链表中的每一个结点&#xff0c;我们可以定义如下的结构体&#xf…

C语言——反转链表

大家好&#xff0c;本人第一次发布博客&#xff0c;目前正在学习数据结构&#xff0c;写博客的目的是一是想分享自己的学习过程&#xff0c;二也是每次写完代码后进行总结。希望大家一起共同学习&#xff01; 现在我正在看《大话数据结构》这本书&#xff0c;每次学习过后我都会…

C语言数据结构之链表

前面的文章我们就一直说&#xff0c;学一个新东西之前一定要弄明白它的作用是什么&#xff0c;我们为什么要用它。之前讲C语言时我们讲到数组&#xff0c;数组的实质是一种顺序储存、随机访问、存储单元连续的线性表&#xff0c;既然存储单元连续&#xff0c;那么对其进行插入和…

C语言来实现链表创建

链表原理理解 链表作为一种线性数据&#xff0c;通过前后节点的指针指向&#xff0c;将所有数据串联起来。为了实现链表数据域的整体耦合&#xff0c;需要额外的指针域来标定前后数据的连接。通过下面的链表结构图&#xff0c;可以非常容易的理解链表的组成结构 头节点作为链表…

链表C语言和C++两种方式实现

一、C语言版本链表&#xff1a; 方向1&#xff1a;无表头 法一&#xff1a;尾插法 #include<stdio.h> #include<malloc.h> //打印 创建 释放 删除某个数 插入某个数 &#xff08;T_T&#xff09;5个功能 struct Node {int data;struct Node* next; }; typedef st…

C语言实现链表创建

C语言实现链表的创建 链表:是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。每个结点包括两个部分&#xf…