当前位置: 首页 > news >正文

java抽奖系统登录下(四)

6.4 关于登录

最简单的登录:

        1、web登录页填写登录信息,前端发送登录信息到后端;

        2、后端接受登录信息,并校验。校验成功,返回成功结果。

        这种登录会出现一个问题,用户1成功登录之后,获取到后台管理页,将这个页面的url分享给用户2,用户2没有进行登录就会直接进入到后台管理页,容易造成信息泄露;

        解决方法:用户在进入后台管理页之前要进行校验;

几种常见的登录验证的方式:

方式1、cookie-session

1、用户带登录的时候,就会把用户信息发送到后端,后端根据用户信息创建一个sessionid,将用户登录的相关信息放入到session中,后续通过sessionid来进行查找校验,并将sessionid传送到前端;

2、前端接收到sieeionid之后将其存入到cookie中,后续在进行登陆之后会携带cookie,后端会根据前端发送过来的cookie解析到其中的sieeionid,通过sessionid来查找是否用这个id所对应的用户消息。如果存在用户信息,则表示之前这个用户登录过,就会放心该用户跳转到其他界面;如果该id没有查找到相关的用户信息,则表示该用户之前没有进行登录过,不会放行;

缺点:1、cookie只在web网页中生成,存在环境限制;

        2、这种方式不能跨域;

        3、cookie只能在本机保存,不能在集群环境中使用;

方式2: token认证

        上图的token是存储在redis,由于redis是可以部署在集群环境中,所以解决了cookie-session的一下缺陷;

        缺点:用户数量大会导致频繁的访问redis校验token,对于内存来说有很大的压力。

方式三:基于token的jwt令牌认证

 

        1、前端的登录信息发送到后端之后,后端基于jwt服务产生一个string类型的字符串,成为jwt令牌,这个令牌是不需要存储在后端的,而是直接返回到前端;

        2、前端使用本地的存储方式,将jwt存储起来,后续在进行操作的话会带着jwt令牌到后端,后端会对jwt令牌进行校验,如果能够正确使用jwt解密,说明校验通过了;

        jwt:实际上是一个加解密的过程,这个过程是依靠jwt独立的工具包来完成和实现的。

        jwt:结构是由负载,签名和头部组成的,由这三部分组成一个串;

6.5 jwt令牌工具类的实现

        该工具类主要完成jwt的加密和解密操作:

 首先引入相关的依赖:

新建jwtutil类:

public class JWTUtil {private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);/*** 密钥:Base64编码的密钥*/private static final String SECRET = "weS2l8Tp9wDFov9ic72l/9VRT3j9aYfhEfi8qwGMDgU=";/*** 生成安全密钥:将一个Base64编码的密钥解码并创建一个HMAC SHA密钥。*/private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET));/*** 过期时间(单位: 毫秒)*/private static final long EXPIRATION = 60*60*1000*24*30;//一个月/*** 生成密钥** @param claim  {"id": 12, "name":"张山"}* @return*/public static String genJwt(Map<String, Object> claim){//签名算法String jwt = Jwts.builder().setClaims(claim)             // 自定义内容(载荷).setIssuedAt(new Date())      // 设置签发时间.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 设置过期时间.signWith(SECRET_KEY)         // 签名算法,和加解密相关.compact();return jwt;}/*** 验证密钥*/
//    Claims是jwt里面定义的对象public static Claims parseJWT(String jwt){if (!StringUtils.hasLength(jwt)){return null;}// 创建解析器, 设置签名密钥JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder().setSigningKey(SECRET_KEY);Claims claims = null;try {//解析tokenclaims = jwtParserBuilder.build().parseClaimsJws(jwt).getBody();}catch (ExpiredJwtException e){// 签名验证失败
//            logger.error("解析令牌错误,jwt:{}", jwt, e);claims = e.getClaims();}return claims;}/*** 从token中获取用户ID*/public static Integer getUserIdFromToken(String jwtToken) {Claims claims = JWTUtil.parseJWT(jwtToken);if (claims != null) {Map<String, Object> userInfo = new HashMap<>(claims);return (Integer) userInfo.get("userId");}return null;}
}

controller层登录接口设计:

    @RequestMapping("/password/login")public CommonResult<UserLoginResult> userPasswordLogin(@Validated @RequestBody UserPasswordLoginParam param) {logger.info("userPasswordLogin UserPasswordLoginParam:{}",JacksonUtil.writeValueAsString(param));UserLoginDTO userLoginDTO = userService.login(param);return CommonResult.success(convertToUserLoginResult(userLoginDTO));}

 service层登录接口实现:

@Overridepublic UserLoginDTO login(UserLoginParam param) {UserLoginDTO userLoginDTO;// 类型检查与类型转换,java 14及以上版本if (param instanceof UserPasswordLoginParam loginParam) {// 密码登录流程userLoginDTO = loginByUserPassword(loginParam);} else if (param instanceof ShortMessageLoginParam loginParam) {// 短信验证码登录流程userLoginDTO = loginByShortMessage(loginParam);} else {throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);}return userLoginDTO;}private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {if (!RegexUtil.checkMobile(loginParam.getLoginMobile())) {throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);}// 获取用户数据UserDO userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));if (userDO == null) {throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);} else if (StringUtils.hasText(loginParam.getMandatoryIdentity())&& !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);}// 校验验证码String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());if (!loginParam.getVerificationCode().equals(code)) {throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);}// 塞入返回值(JWT)Map<String, Object> claim = new HashMap<>();claim.put("id", userDO.getId());claim.put("identity", userDO.getIdentity());String token = JWTUtil.genJwt(claim);UserLoginDTO userLoginDTO = new UserLoginDTO();userLoginDTO.setToken(token);userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));return userLoginDTO;}private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {UserDO userDO = null;// 判断手机登录还是邮箱登录if (RegexUtil.checkMail(loginParam.getLoginName())) {// 邮箱登录// 根据邮箱查询用户表userDO = userMapper.selectByMail(loginParam.getLoginName());} else if (RegexUtil.checkMobile(loginParam.getLoginName())) {// 手机号登录// 根据手机号查询用户表userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));} else {throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);}// 校验登录信息if (null == userDO) {throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);} else if (StringUtils.hasText(loginParam.getMandatoryIdentity())&& !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {// 强制身份登录,身份校验不通过throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);} else if (!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())) {// 校验密码不同throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);}// 塞入返回值(JWT)Map<String, Object> claim = new HashMap<>();claim.put("id", userDO.getId());claim.put("identity", userDO.getIdentity());String token = JWTUtil.genJwt(claim);UserLoginDTO userLoginDTO = new UserLoginDTO();userLoginDTO.setToken(token);userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));return userLoginDTO;}

使用postman对登录进行测试:

账号密码:

验证码登录:

 开启redis缓存验证码:service redis-server start

发送验证码:

验证码登录:

6.6 前端登录完善

进行前端测试:

密码登录:

短信验证码登录:

登录成功之后进入新的界面:

在登录页面点击注册进入注册见面,注册成功之后返回登录界面:

6.7 登录拦截器

        在设置好jwt令牌登陆之后,用户进行登录操作,会得到后端传过来的jwt令牌,其次用户会拿着这个令牌去访问其他界面的时候,后端会对这个jwt令牌进行校验,这里采用的是拦截器,当然不是所有的请求都需要校验,会进行相关配置;

登录拦截器:

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {/**登录拦截器* 预处理,业务请求之前调用* @param request* @param response* @param handler* @return*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 获取请求头,jwt是在request的请求头中的String token = request.getHeader("user_token");log.info("获取token:{}", token);log.info("获取路径:{}", request.getRequestURI());// 令牌解析Claims claims = JWTUtil.parseJWT(token);if (claims == null) {log.error("解析JWT令牌失败!");response.setStatus(401);return false;}log.info("解析JWT令牌成功!放行");return true;}
}

配置登录拦截资源:

@Configuration
public class AppConfig implements WebMvcConfigurer {//配置项@Autowiredprivate LoginInterceptor loginInterceptor;private final List<String> excludes = Arrays.asList("/**/*.html","/css/**","/js/**","/pic/**","/*.jpg","/*.png","/favicon.ico","/**/login","/register","/verification-code/send");@Override//添加自定义的登录拦截器public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(excludes);}
}

ps:关于登录的内容就到这里了,谢谢观看!!!

相关文章:

java抽奖系统登录下(四)

6.4 关于登录 最简单的登录&#xff1a; 1、web登录页填写登录信息&#xff0c;前端发送登录信息到后端&#xff1b; 2、后端接受登录信息&#xff0c;并校验。校验成功&#xff0c;返回成功结果。 这种登录会出现一个问题&#xff0c;用户1成功登录之后&#xff0c;获取到后台…...

解决阿里云轻量级服务器 Ubuntu 24.04.1 LTS 没网也 ping 不通 8.8.8.8 以及 route -n 没有输出任何转发信息

事情发生在两天前&#xff0c;位于公网的阿里云轻量级服务器&#xff08;Ubuntu 24.04.1 LTS&#xff09;忽然没网。主要是上次上服务器进行配置已经是一个多月前&#xff0c;最近也没有做什么事情&#xff0c;就忽然没网了&#xff0c;让人纳闷。更主要的是&#xff0c;上次备…...

跨域问题及其解决方案

跨域问题及其解决方案 在Web开发中&#xff0c;跨域问题是一个常见的安全限制&#xff0c;它涉及到浏览器的同源策略&#xff08;Same-Origin Policy&#xff09;。本文将详细解释跨域问题的原因、影响以及几种常见的解决方案&#xff0c;并提供在Java中的实现方法。 目录 跨…...

在CentOS中安装和卸载mysql

在CentOS7中安装和卸载mysql 卸载mysql1、查看是否安装过mysql2、查看mysql服务状态3、关闭mysql服务4、卸载mysql相关的rpm程序5、删除mysql相关的文件6、删除mysql的配置文件my.cnf 安装mysql1、下载mysql相关的rpm程序2、检查/tmp临时目录权限3、安装mysql前的依赖检查3、安…...

React简单入门 - [Next.js项目] - 页面跳转、AntD组件、二级目录等

须知 1Next.js 官网(英文)https://nextjs.org/2Next.js 文档(中文)https://nextjscn.org/docs/3Ant Design组件总览https://ant-design.antgroup.com/components/overview-cn4tailwindcss类名大全 官网https://www.tailwindcss.cn/docs/justify-content 5tailwindcss常用类…...

Redis安装和Python练习(Windows11 + Python3.X + Pycharm社区版)

环境 Windows11 Python3.X Pycharm社区版 思路 1 github下载redis压缩包 &#xff0c;安装并启动redis服务&#xff0c;在客户端连接redis服务。 2 在pycharm中运行python程序&#xff0c;连接redis服务&#xff0c;熟悉redis的使用和巩固python语言。 3 python开发环境…...

Sqoop脚本编写(Mysql---->>hdfs)

目录 语法手册编写方式脚本文件类型文件编写.jar路径指定 执行效果执行方式效果 语法手册 参考博客 编写方式 脚本文件类型 只要是可读的文件即可&#xff08;.txt或者.sh等其他类型&#xff0c;不带文件后缀也可以&#xff0c;但二进制文件最好不要&#xff09; 文件编写…...

帝可得项目redis连接不上

首先我一切配置都没问题&#xff1a; 1. redis-server启动 2. 可视化界面显示redis已连接 原因&#xff1a; 不知道是不是因为不同版本的问题(因为我之前的sky就没这个问题) 这里把password改成auth就可以了...

JS中this的值详细讲解以及面试指向练习

this 的值取决于它出现的上下文&#xff1a;函数、类或全局。 在函数内部&#xff0c;this 的值取决于函数如何被调用&#xff0c;this 是语言在函数体被执行时为你创建的绑定 对于典型的函数&#xff0c;this 的值是函数被访问的对象。换句话说&#xff0c;如果函数调用的形…...

显示浮动式窗口的方法

文章目录 1 概念介绍2 使用方法3 示例代码我们在上一章回中介绍了AlertDialog Widget相关的内容,本章回中将介绍BottomSheet Widget.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里说的BottomSheet是一种弹出式窗口,和上一章回中介绍的AlertDialog类似,但是也…...

FireFox火狐浏览器企业策略禁止更新

一直在用火狐浏览器&#xff0c;但是经常提示更新&#xff0c;进入浏览器右上角就弹出提示&#xff0c;比较烦。多方寻找&#xff0c;一直没有找到合适的方案&#xff0c;毕竟官方没有给出禁用检查更新的选项&#xff0c;甚至about:config里都没有。 最终找到了通过企业策略控…...

C++类的运算符重载

目标 让自定义的类直接使用运算符运算 代码 头文件及类定义 #include <iostream>using namespace std; class Complex {int rel;int vir; public:void show(){cout <<"("<<this->rel<<","<<this->vir<<&quo…...

泷羽Sec学习笔记-zmap搭建炮台

zmap搭建炮台 zmap扫描环境&#xff1a;kali-linux 先更新软件库 sudo apt update 下载zmap sudo apt install zmap 开始扫描(需要root权限) sudo zmap -p 80 -o raw_ips.txt 代码解析&#xff1a; sudo&#xff1a;以超级用户&#xff08;管理员&#xff09;权限运行…...

分析M0G突破后急剧下跌内因,x.game阐述不利面延续多久

MOG最新消息显示&#xff0c;美国唐纳德-的一则声明公开表示支持一种基于以太坊网络ERC-20代币标准的病毒式meme代币——Mog Coin&#xff08;MOG&#xff09;&#xff0c;这一消息迅速发酵。然而&#xff0c;令人意想不到的是&#xff0c;在这位全球知名政治人物的背书之后&am…...

网络爬虫全解析

一、网络爬虫基础要点 &#xff08;一&#xff09;爬虫原理 目标确定&#xff1a;明确需要抓取数据的网站或网页范围&#xff0c;例如针对特定电商平台抓取商品信息&#xff0c;或聚焦新闻网站获取新闻报道内容&#xff0c;要考量数据的价值与用途。URL 解析&#xff1a;理解网…...

《孤岛惊魂4》无法启动提示缺少“msvcp100.dll”快速修复方法!

《孤岛惊魂4》缺少msvcp100.dll的解决之道 在探索《孤岛惊魂4》这款充满惊险与刺激的射击游戏时&#xff0c;玩家可能会遇到一些意外的障碍&#xff0c;其中之一便是“缺少msvcp100.dll”的错误提示。这个错误不仅让游戏无法正常启动&#xff0c;还可能让玩家对游戏的热情大打…...

GS-SLAM论文阅读--RGBDS-SLAM

前言 最近GS-SLAM领域的工作层出不穷&#xff0c;有很多不错的工作出现。接下来慢慢写一下相关博客。 文章目录 前言1.背景介绍2.关键内容2.1 3D多层次金字塔高斯喷溅2.2 紧密耦合多特征重构优化2.3总体流程 3.文章贡献4.个人思考 1.背景介绍 高保真重建是密集SLAM的关键。最…...

条件编译->enable_if和 if constexpr使用区别

enable_if 和 if constexpr 是 C 中用于控制编译或运行时条件的重要工具&#xff0c;它们各有不同的用途和使用场景。以下是它们的主要区别&#xff1a; 1. enable_if std::enable_if 是一个类型特征&#xff0c;用于在编译时根据条件选择类型。常用于模板元编程&#xff0c;…...

介绍一下CSS中伪类和伪元素的概念

一、伪类&#xff08;Pseudo - Classes&#xff09; 1. 定义 伪类是添加到选择器的关键字&#xff0c;用于定义元素的特殊状态。这些状态不是由文档树中的结构或属性来表示&#xff0c;而是基于用户行为&#xff08;如鼠标悬停&#xff09;、元素状态&#xff08;如被选中&am…...

【橘子ES】熔断器Circuit breaker

一、相关概念 我们在日常的开发中&#xff0c;关于服务之间的熔断操作似乎很常见&#xff0c;当请求超过了我们服务所认为可以承受的一个上限阈值的时候&#xff0c;我们为了保护服务不会被进一步的高负载压崩溃&#xff0c;我们有时候会选择熔断请求&#xff0c;此时服务不再…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...

微服务通信安全:深入解析mTLS的原理与实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言&#xff1a;微服务时代的通信安全挑战 随着云原生和微服务架构的普及&#xff0c;服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...