4.2 配置Mysql与注册登录模块(中)

2023-11-08

学习目标

  1. jwt验证
  2. 后端的API
  3. 前端登录注册页面

学习内容

前端和后端会有跨域问题,不用传统的session验证,而使用JWT方式验证。

http://localhost:3000/logout 退出springSecurity验证;
http://localhost:3000/login


后端

这节课前端后端代码都会有,登陆验证注册;
登陆的逻辑,很多url对应有很多页面,每个页面的权限不一样。
登录一次只要不关闭浏览器就可以访问其它页面。

每个URL都会对应一个controllert

以前传统的session验证方式

在这里插入图片描述

现在很多应用前端后端可能会有跨域的问题,如有多个端,app端,web端;现在session不太适用,因为需要把session复制多份。
即现在应用有很多服务,每个服务是一个端,想通过一个身份去登录所有的后端时,需要将sessionID复制很多分,放到多台服务器上面,比较麻烦。

JWT验证方式

JWT验证的优势:
(1) 解决跨域
(2) 不需要在服务端存储

比如会有多个服务器端,那么只需要一个令牌就可以访问多个服务器。

原理: 原来seesion的方式,一个用户登陆成功之后,需要赋给他一个sessionID,现在给他一个JWT的Token. 服务器给他一个token之后 ,自己是不需要存储任何信息的。
将userID或者其它信息加入到JWT token里面,

简化版逻辑:
在这里插入图片描述(1)密钥是存储在服务器的,对用户不公开,是一个随机字符串自己定义的
(2)hash函数或者加密函数,加密成一个字符串,不可逆
(3)JwtToken = userID+ 加密(hash)后的信息 返回给用户,完全存储到客户端;

未来服务器验证的时候,将接收到的信息,将第一段加上密钥进行加密,看加密后的结果是否与以前加密的信息一致

这节课目的是把session 修改为JWT

两个疑惑:
(1) 篡改数据,冒充UserID去访问,不可行,hash函数加密结果会变;
(2)JwtToken是存储在用户端本地的,如果被窃取,那就是自己的问题,活该。

token一般是存储在用户本地的,浏览器的localstory里面;

优化方法:一般给用户传两个token,一个是access-token(有效时间比较短,如5分钟) ;另一个是refresh-token(有效时间比较长14天);
当每次向服务器发送请求,
带access-token,使用有效时间比较短的令牌;
当短令牌有效期过去之后,再使用Post请求重新根据refresh-koen再获取一个新的token。
在这里插入图片描述

Get请求:明文不安全
Post请求: 安全


这节课的逻辑,登陆页面登录之后会获得一个JWT-Token;服务器不需要存储任何信息的,用户得到之后token存到浏览器,之后每次访问服务的时候,就带上这个token(令牌)。
在这里插入图片描述


JWT工具类

实现utils.JwtUtil类,为jwt工具类,用来创建、解析jwt token
作用
(1)是将一个字符串加上密钥,加上有效期变成一个加密后的字符串;
(2)另外一个作用将一个令牌将userID解析出来

(1)加三个依赖到pom文件

  • jjwt-api
  • jjwt-impl
  • jjwt-jackson

(2)复制工具类JwtUtil类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Component
public class JwtUtil {
    public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14;  // 有效期14天
    public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac";

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
        return builder.compact();
    }

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }

        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)
                .setSubject(subject)
                .setIssuer("sg")
                .setIssuedAt(now)
                .signWith(signatureAlgorithm, secretKey)
                .setExpiration(expDate);
    }

    public static SecretKey generalKey() {
        byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
    }

    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(jwt)
                .getBody();
    }
}

(3)创建Filter工具类

实现config.filter.JwtAuthenticationTokenFilter类,用来验证jwt token,如果验证成功,则将User信息注入上下文中

import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.User;
import com.kob.backend.service.impl.utils.UserDetailsImpl;
import com.kob.backend.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserMapper userMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("Authorization");

        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        token = token.substring(7);

        String userid;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userid = claims.getSubject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        User user = userMapper.selectById(Integer.parseInt(userid));

        if (user == null) {
            throw new RuntimeException("用户名未登录");
        }

        UserDetailsImpl loginUser = new UserDetailsImpl(user);
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, null);

        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}


(4) 配置config.SecurityConfig类,放行登录、注册等接口

import com.kob.backend.config.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/user/account/token/", "/user/account/info/").permitAll()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated();

        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

数据库修改

修改表
在这里插入图片描述
创建一个列,存储头像
存储的都是头像链接;以后图片可以存储到图床.在这里插入图片描述
在这里插入图片描述

修改pojo,因为实体是和数据库相匹配的。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    // 在mabatis-plus中 最好不要使用int ,而去使用对象Integer
    @TableId(type = IdType.AUTO)  // 目的是让id自增(mybatis-plus里面的)
    private Integer id;
    private String username;
    private String password;
    private String photo;


}

写具体业务API

实现三个API

在这里插入图片描述写api的流程,三个地方
(1) 写service里面写接口,
InfoService,LoginService, RegisterService
(2) 在service / impl写接口的实现
(3) 写controller里面,调用service

RegisterService接口和 LoginService接口是公开的,没有帐号之前不能锁住
登陆成功之后就可以获取用户的信息了。

在这里插入图片描述

根据token获取用户信息

这里使用第一个用户的token就获取第一个用户的信息
在这里插入图片描述在这里插入图片描述

试验: 使用第二个用户登陆验证,要更换对应的token
token =用户id+ 加密信息(用户id+随机密钥)

结果:使用谁的token就获取谁的信息

注册API


前端

在这里插入图片描述

这节课实现了登录效果

在这里插入图片描述在这里插入图片描述在这里插入图片描述

退出登录时只需要在本地将token删除掉就行,服务器中没有存储token信息
删除在前端操作
下节课实现注册页面

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

4.2 配置Mysql与注册登录模块(中) 的相关文章

  • 如何在MySQL查询结果中显示序号

    我有一些简单的查询 SELECT foo bar FROM table 我想你现在的结果是什么样的 我想要做的是根据查询结果中出现的数据数量来显示一些序列号 就像AUTO INCREMENT 这并不意味着我想出示身份证 我想要的结果是这样的
  • 为 Codeigniter 中的 foreach() 提供的参数无效

    我收到错误消息 我的视图中 foreach 的参数无效 我想显示 mysql 表中的所有条目 但我不断收到错误消息 我是 Codeigniter 的新手 无法真正弄清楚如何解决这个问题 代码如下 我的模型 display branch ph
  • 如何从准备好的语句中获取标量结果?

    是否可以将准备好的语句的结果设置为变量 我正在尝试创建以下存储过程 但失败了 第 31 行出现错误 1064 42000 您的 SQL 语法有错误 检查与您的 MySQL 服务器版本相对应的手册 了解在 stmt USING m c a 附
  • 在MySQL中永久设置auto_increment_offset

    我以 root 身份运行命令 set auto increment offset 2 但从其他连接上看不到效果 为什么不 它是全球性的 From http dev mysql com doc refman 5 1 en replicatio
  • 两个表之间可以有两种关系吗?

    有两个表 EMPLOYER 和 EMPLOYEE 由于每个 EMPLOYEE 都被分配给一个 EMPLOYER 因此他们之间存在 1 N 关系 简单的事情 但我也希望能够模拟一种情况 每个雇主都可以选择他的one最喜欢的员工 他最好什么也不
  • MySql 5.0 可以查看位于另一台服务器上的表吗

    MySql 5 0 视图可以使用位于另一台服务器上的表吗 创建这样的视图的语法是什么 联合表 http dev mysql com doc refman 5 0 en federated storage engine html http d
  • mysql utf8_general_ci 区分大小写

    我有一个 mysql 数据库 我使用 utf8 general ci 不区分大小写 在我的表中 我有一些列 例如 ID 和区分大小写的数据 例如 iSZ6fX 或 AscSc2 为了区分大写和小写 最好只在这些列上设置 utf8 bin 如
  • 我不小心锁定了 MySQL 的 root

    我在 OS X 上使用 MySQL 并使用删除了所有 root 用户DROP USER 然后我又添加了其中一些并做了GRANT ALL on to root localhost 然后在验证确实是的之后注销 我可以登录并执行一些特权操作 不幸
  • 在 Entity-Framework Core 中批量插入到 MySQL [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个由约 10 000 个对象组成的列表 比方说类Person 我需要将其插入到 MySQL 表中
  • 提交ajax表单并停留在同一页面不起作用

    我想将用户的评论存储在我的数据库中 当用户提交时 我不想将他们重定向到新页面 我有以下代码 但它不起作用 我的 HTML 代码
  • 保存用户的身高和体重

    我应该如何将用户的身高和体重存储在MySQL数据库中 以便我可以使用这些信息来查找特定身高或体重内的用户 另外 我需要能够以英制或公制显示此信息 我的想法是存储以厘米为单位的身高和以公斤为单位的体重信息 我更喜欢公制而不是英制 我什至可以让
  • MySQL 命令输出在命令行客户端中太宽[重复]

    这个问题在这里已经有答案了 我在用mysql终端模拟器中的命令行客户端lxterminal在Ubuntu中 当我运行以下命令时 mysql gt select from routines where routine name simplep
  • SQL Server到Mysql迁移(使用Mysql Workbench)数据传输错误

    我正在使用 Mysql Work bench 6 3 将数据库从 MS Sql server 2008 迁移到 Mysql 在 批量数据传输 期间出错并出现以下警告 这种情况仅发生在像 varchar char 这样的列类型上 当我尝试使用
  • 用于分页的php示例脚本[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 任何人都可以建议一个好的分页 php 脚本 其中人们想要分页显示数据库中的大量项目 以下链接可以帮助您
  • MySQL - 此版本的 MySQL 尚不支持“LIMIT 和 IN/ALL/ANY/SOME 子查询”

    这是php编码我正在使用的 Last Video db gt fetch all SELECT VID thumb FROM video WHERE VID IN SELECT VID FROM video WHERE title LIKE
  • 使用 JOIN 和 UNION 合并不同表中的记录

    我需要创建一个查询来组合两个表中的数据 我认为可能是 JOIN 和 UNION 的组合 在此示例中 我需要列出状态处于活动状态的所有姓名 仅一次 并将他们的葡萄酒 苏打水 晚餐 甜点和水果偏好组合起来 按姓名排序 我不确定单独的 JOIN
  • 如何将另一列的整数值添加到日期列?

    我试图将整数添加到日期 但出现以下错误 1064 你的 SQL 语法有错误 检查与您的 MySQL 服务器版本相对应的手册 了解在第 6 行的 wp OrderDate INTERVAL WPProduct Duration DAY AS
  • 在 MySQL 中搜索多个单词

    我使用 HTML 表单来允许用户查找数据库表中的条目
  • 无法在 Centos 上安装 php-mysqli 扩展

    我正在尝试将 mysqli 扩展安装到 php yum install php mysqli 我收到下一个错误 Transaction Check Error file usr share mysql charsets Index xml
  • PHP 中的嵌套 JSON 输出

    我正在为 iOS 应用程序构建 API 并尝试将 mySQL 数据转换为 JSON 字符串进行处理 所需的输出将需要顶级订单详细信息 例如客户名称和地址 然后是订购的产品子数组 我需要的两个表中有相当多的字段 我希望拥有所有字段 我已经构建

随机推荐

  • 功能强大的国产Api管理工具

    前言 如果你是一名Java后端开发工程师 像Swagger Postman RAP这些工具 应该再熟悉不过了吧 为我们的接口开发工作带来了很多的便捷 不过因为这些都是独立的框架 之间并不存在互通性 因此在多个框架间协调的时候 不可避免的会带
  • Anaconda下Jupyter Notebook执行OpenCV中cv2.imshow()报错(错误码为1272)网上解法汇总记录和最终处理方式

    零 我设备的相关信息 Python 3 8 8 Anaconda3 2021 05 查询匹配python3 8 的OpenCV匹配版本为 4 1 4 2 我最后安装4 2 0 32版本 如下我记录了 从发现问题 到不断试错 最后解决问题 的
  • 电视制式 NTSC PAL SECAM

    电视制式 电视的制式是指电视信号的标准 目前各国的电视制式不尽相同 如附件1 2 制式的区分主要在于其帧频 场频 的不同 分解率的不同 信号带宽以及载频的不同 色彩空间的转换关系不同等 电视制式现在有模拟和数字信号和数字信号两种 模拟制式一
  • 【Linux】进程篇(补):守护进程

    文章目录 1 补充 1 1 查看 1 2 控制进程组的方式 2 创建守护进程 step1 忽略信号 step2 让自己不是组长 step3 setsid 函数 给调用函数设置新的会话和进程组 ID step4 chdir 函数 可以改变守护
  • Android Service最全面的解析

    本篇文章再次来自 刘明渊 话说刘明渊已经是我公众号的老熟人了 这是第三次发表他投稿的文章 前两篇关于Intent的译文都广受大家好评 而本篇对于Service的译文同样精彩 其实像这种官方文档翻译类文章的投稿我都是非常欢迎的 因为官方文档的
  • 基于内容的图像检索技术(1):从特征到检索

    作者 赵丽丽 链接 https zhuanlan zhihu com p 46735159 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 基于内容的图像检索 CBIR Content Based Image
  • 解决pandas中boxplot函数默认添加大标题“Boxplot grouped by ”

    问题 如何删除下图的 Boxplot grouped by path num 生成上图的代码 fig ax plt subplots figsize 8 6 df df path num 2 boxplot column travel ti
  • 【软件工程

    概念 耦合 coupling 是对两个模块之间联接程度的一种度量 模块间的依赖程度越大 则其耦合程度也就越大 反之 模块间的依赖程度越小 则其耦合程度也就越小 很显然 为了使软件具有较好的可维护性和可修改性 模块间的关联程度即耦合程度应越小
  • 网络安全鹰眼靶场(基础关)

    目录 前言 key在哪里 再加密一次你就得到key啦 猜猜这是经过了多少次加密 据说MD5加密很安全 真的是么 种族歧视 HAHA浏览器 key究竟在哪里呢 key又找不到了 冒充登陆用户 比较数字大小 本地的诱惑 就不让你访问 前言 靶场
  • CodeSmith 使用教程(3): 自动生成Yii Framework ActiveRecord

    上例介绍了使用CodeSmith编写代码模板的基本方法 本例实现一个较为实用的代码模板 通过数据库自动为Yii Framework生成所需要的ActiveRecord 类 本例通过修改Yii Framework 开发教程 26 数据库 Ac
  • numpy明明有高版本却显示版本不够

    不知道和我上篇文章添加Jupyter notebook代码提示是否有关系 大概率 在进行导入numpy库的时候出现了以下问题 真的特别离奇 我之前都用得好好的 怎么突然不行了 接下来就对库版本进行折腾 以下操作均在管理员运行的Anacond
  • 全球计算机出货量排名,2018年全球电脑出货量排名:联想夺冠,惠普戴尔分列二三...

    作者 虎龙吟 美国当地时间2019年1月10日 Gartner发布了2018年全球个人电脑出货量数据报告 根据Gartner发布的数据 2018年第四季度 全球个人电脑出货量达到6860万台 比2017年第四季度下降了4 3 根据Gartn
  • chatglm2-6b在P40上做LORA微调

    背景 目前 大模型的技术应用已经遍地开花 最快的应用方式无非是利用自有垂直领域的数据进行模型微调 chatglm2 6b在国内开源的大模型上 效果比较突出 本文章分享的内容是用chatglm2 6b模型在集团EA的P40机器上进行垂直领域的
  • 萌妖出没服务器维护电视版,萌妖出没-萌妖出没手游官网版预约-9k9k手游网

    萌妖出没是一款根据经典动漫改编而成的策略竞技手游 游戏中还原了众多经典的场景 玩家在玩游戏的过程中还有回味众多经典的动漫情节 众多宠物精灵等你来收集 打造强大的精灵战队 带领它们不断的战斗冒险 体验其中的无穷乐趣 感兴趣的玩家随时可以来下载
  • 牛客网——字符串排序(C++)

    题目描述 编写一个程序 将输入字符串中的字符按如下规则排序 规则 1 英文字母从 A 到 Z 排列 不区分大小写 如 输入 Type 输出 epTy 规则 2 同一个英文字母的大小写同时存在时 按照输入顺序排列 如 输入 BabA 输出 a
  • R语言 第四章 初级绘图(3)核密度图,小提琴图,QQ图,星状图,等高图,固定颜色选择函数,渐变色生成函数,主体调色板,rainbow(),RcolorBrewer包

    关注公众号凡花花的小窝 收获更多的考研计算机专业编程相关的资料 绘制其他图形 核密度图 sm包中sm density compare函数用于绘制核密度图 核密度图是用一条密度曲线而不是通过柱状来展示连续型变量的分布 相比直方图 密度图的一个
  • getUserProfile:fail 调用失败?getUserProfile:fail can o

    一般Fail原因有很多 如果fail函数的参数返回结果有具体的提示错误 比如长度关键字等问题 那么根据提示直接更改就行 还有一种情况就是我们使用测试号 Uni开发时 我们调用getUserProfile函数返回错误 我们首先要考虑AppId
  • 分享三个不同目录双向更新的实用方法

    分享三个不同目录双向更新的实用方法 方法一 rsync 判断脚本 进行双向更新 方法二 使用rsync的 u选项 方法三 使用rsync inotify监控工具 扩展 方法一 rsync 判断脚本 进行双向更新 脚本内容如下 bin bas
  • 一起来!白嫖Amazon DynamoDB!!!

    Amazon DynamoDB简介 Amazon DynamoDB是由Amazon Web Services AWS 提供的一种快速 灵活 全托管的NoSQL数据库服务 支持文档和键 值数据模型 它具有自动扩展 低延迟 高可靠性 高吞吐量等
  • 4.2 配置Mysql与注册登录模块(中)

    目录 学习目标 学习内容 后端 JWT工具类 数据库修改 写具体业务API 根据token获取用户信息 注册API 前端 这节课实现了登录效果 学习目标 jwt验证 后端的API 前端登录注册页面 学习内容 前端和后端会有跨域问题 不用传统