从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(五) 实现登录功能

news2025/2/28 15:05:00

1.登录页面

  完善登录页面  和注册差不多 直接copy signUpPage 内容 再稍微修改下

import { useState } from "react";
import { useAuthStore } from "../store/useAuthStore";
import { MessageSquare,Mail,Lock,Eye, EyeOff,Loader2} from "lucide-react";
import {Link} from "react-router-dom"



const LoginPage = () => {
  const [showPassword, setShowPassword] = useState(false)
  const[formData,setFormData] = useState({
    email:"",
    password:""
  })

  const {login,isLogging} = useAuthStore()

  const handleSubmit = async (e) => {
    e.preventDefault()
    await login(formData)
  }
  return (
    <div className="min-h-screen grid lg:grid-cols-2">
       {/*left side*/}
        <div className="flex flex-col justify-center items-center p-6 sm:p-12">
            <div className="w-full mt-10">
                {/* logo */}
                <div className="text-center mb-8">
                    <div className="flex flex-col items-center gap-2 group">
                        <div className="size-12 rounded-xl bg-primary/10 flex items-center justify-center
                        group-hover:bg-primary/20 transition-colors">
                            <MessageSquare className="size-6 text-primary"></MessageSquare>
                        </div>
                        <h1 className="text-2xl font-bold mt-2">欢迎回来</h1>
                        <p className="text-base-content/60">登录账户</p>
                    </div>
                </div>
                {/* form */}
                <form onSubmit={handleSubmit} className="space-y-6">
                    
                    <div className="form-control">
                        <label className="label">
                            <span className="label-text font-medium">邮箱</span>
                        </label>
                        {/* 输入框 */}
                        <div className="relative">
                            <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <Mail className="size-5 text-base-content/40" />
                            </div>
                            <input 
                                type="text"
                                className={`input input-bordered w-full pl-10`}
                                placeholder="请输入邮箱地址"
                                value={formData.email}
                                onChange={(e)=> setFormData({...formData,email:e.target.value})}
                            >

                            </input>
                        </div>
                    </div>

                    <div className="form-control">
                        <label className="label">
                            <span className="label-text font-medium">密码</span>
                        </label>
                        {/* 输入框 */}
                        <div className="relative">
                            <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <Lock className="size-5 text-base-content/40" />
                            </div>
                            <input 
                                type={showPassword ? "text" : "password"}
                                className={`input input-bordered w-full pl-10`}
                                placeholder="请输入密码"
                                value={formData.password}
                                onChange={(e)=> setFormData({...formData,password:e.target.value})}
                            >
                            </input>
                            
                            <button
                                type="button"
                                className="absolute inset-y-0 right-0 pr-3 flex items-center"
                                onClick={()=> setShowPassword(!showPassword)}
                            >
                                {showPassword ? (<EyeOff className="size-5 text-base-content/40" />) : (<Eye className="size-5 text-base-content/40" />)}
                            </button>
                        </div>
                    </div>

                    <button 
                        type="submit"
                        className="btn btn-primary w-full"
                        disabled={isLogging}
                    >

                        {isLogging ? (
                            <>
                                <Loader2 className="size-5 animate-spin"/>
                                Loading...
                            </>
                        ):(
                            "登录"
                        )}
                    </button>
                </form>

                <div className="text-center">
                    <p className="text-base-content/60">
                        没有账号?{""}
                        <Link to="/signup" className="link link-primary">去注册</Link>
                    </p>
                </div>
            </div>
        </div>

        {/* right side */}
       
    </div>
  )
}

export default LoginPage

这时我们的前端页面就有了

 

2.测试

输入我们注册号的账号 登录 提示登录成功!

3.页面完善

 现在我们登录和注册右侧缺一部分 我们补充上

在web下 新建components文件夹 再创建AuthImagePattern.jsx

const AuthImagePattern = ({title, subTitle}) => {
    return (
      <div className="hidden lg:flex items-center justify-center bg-base-200 p-12">
         <div className="max-w-md text-center mt-10">
          <div className="grid grid-cols-3 gap-3 mb-8">
              {[...Array(9)].map((_,i)=>(
                  <div key={i}
                      className={`aspect-square rounded-2xl bg-primary/10 ${i%2===0?"animate-pulse":""}`}
                  >
                  </div>
              ))}
          </div>
          <h2 className="text-2xl font-bold mb-4">{title}</h2>
          <p className="text-base-content/40">{subTitle}</p>
         </div>
      </div>
    )
  }
  export default AuthImagePattern

然后在singUpPage 和 LoginPage  引入即可

import AuthImagePattern from "@/components/AuthImagePattern" 在right side使用

 {/* right side */}

        <AuthImagePattern title="加入我们" subTitle="发现新朋友,分享瞬间,享受乐趣,与你最心爱的人们保持联系。"/>

效果如图

4.认证优化 

问题思考  当我们用户已经登录了 登录token没有过期 这时候我们应该让用户跳到首页 如果token过期了 就重定向到login 页面  这时获取用户信息之前就需要进行用户是否登录的验证 使用中间件来实现此功能

 回到后端server  新建文件夹middleware 新建auth.middleware.js

在auth.route.js  中新增一个路由

// 身份验证

router.get('/check', protectRoute, checkAuth)

在auth.controller.js中 增加 checkAuth 方法 获取返回的用户信息

// 获取登录信息

export const checkAuth =  (req,res) => {

    try {

        res.status(200).json(req.user)

    } catch (err) {

        res.status(500).json({ message: '内部服务器错误' })

    }

}

useAuthStore.js 补充

  isCheckingAuth: false, // 是否在获取用户信息中状态

//  获取用户信息方法

    checkAuth: async() => {

        // 获取当前用户信息

        try {

            const res = await axiosInstance.get('/auth/check')

            set({authUser: res.data})

            // 刷新页面 判断是否登录

            get().connectSocket()

        } catch (error) {

            console.log("useAuthStore checkAuth error",error.message)

            set({authUser: null})

        } finally {

            set({isCheckingAuth: false})

        }

    },

 修改App.jsx

验证结果 如图checkAuth接口 获取到了用户信息跳转到了 homePage

 

ok   这篇 就这样把  有问题欢迎评论留言!!喜欢的来个3连 谢谢!! 下篇 咱实现导航栏和 修改个人信息 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2307443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】Logistic回归#1基于Scikit-Learn的简单Logistic回归

主要参考学习资料&#xff1a; 《机器学习算法的数学解析与Python实现》莫凡 著 前置知识&#xff1a;线性代数-Python 目录 问题背景数学模型类别表示Logistic函数假设函数损失函数训练步骤 代码实现特点 问题背景 分类问题是一类预测非连续&#xff08;离散&#xff09;值的…

8.Dashboard的导入导出

分享自己的Dashboard 1. 在Dashboard settings中选择 JSON Model 2. 导入 后续请参考第三篇导入光放Dashboard&#xff0c;相近

next.js-学习2

next.js-学习2 1. https://nextjs.org/learn/dashboard-app/getting-started2. 模拟的数据3. 添加样式4. 字体&#xff0c;图片5. 创建布局和页面页面导航 1. https://nextjs.org/learn/dashboard-app/getting-started /app: Contains all the routes, components, and logic …

视频推拉流EasyDSS直播点播平台授权激活码无效,报错400的原因是什么?

在当今数字化浪潮中&#xff0c;视频推拉流 EasyDSS 视频直播点播平台宛如一颗璀璨的明珠&#xff0c;汇聚了视频直播、点播、转码、精细管理、录像、高效检索以及时移回看等一系列强大功能于一身&#xff0c;全方位构建起音视频服务生态。它既能助力音视频采集&#xff0c;精准…

【论文详解】Transformer 论文《Attention Is All You Need》能够并行计算的原因

文章目录 前言一、传统 RNN/CNN 存在的串行计算问题二、Transformer 如何实现并行计算&#xff1f;三、Transformer 的 Encoder 和 Decoder 如何并行四、结论 前言 亲爱的家人们&#xff0c;创作很不容易&#xff0c;若对您有帮助的话&#xff0c;请点赞收藏加关注哦&#xff…

Framework层JNI侧Binder

目录 一&#xff0c;Binder JNI在整个系统的位置 1.1 小结 二&#xff0c;代码分析 2.1 BBinder创建 2.2 Bpinder是在查找服务时候创建的 2.3 JNI实现 2.4 JNI层android_os_BinderProxy_transact 2.5 BPProxy实现 2&#xff09;调用IPCThreadState发送数据到Binder驱动…

Excel大文件拆分

import pandas as pddef split_excel_file(input_file, output_prefix, num_parts10):# 读取Excel文件df pd.read_excel(input_file)# 计算每部分的行数total_rows len(df)rows_per_part total_rows // num_partsremaining_rows total_rows % num_partsstart_row 0for i i…

OpenCV计算摄影学(7)HDR成像之多帧图像对齐的类cv::AlignMTB

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该算法将图像转换为‌中值阈值位图‌&#xff08;Median Threshold Bitmap&#xff0c;MTB&#xff09;&#xff1a; 1.位图生成‌&#xff1a;…

Axure PR 9 中继器 03 翻页控制

大家好&#xff0c;我是大明同学。 接着上期的内容&#xff0c;这期内容&#xff0c;我们来了解一下Axure中继器图表翻页控制。 预览地址&#xff1a;https://pvie5g.axshare.com 翻页控制 1.打开上期RP 文件&#xff0c;在元件库中拖入一个矩形&#xff0c;宽值根据业务实际…

IO流(师从韩顺平)

文章目录 文件什么是文件文件流 常用的文件操作创建文件对象相关构造器和方法应用案例 获取文件的相关信息应用案例 目录的操作和文件删除应用案例 IO 流原理及流的分类Java IO 流原理IO流的分类 IO 流体系图-常用的类IO 流体系图&#xff08;重要&#xff01;&#xff01;&…

Spring Boot集成Jetty、Tomcat或Undertow及支持HTTP/2协议

目录 一、常用Web服务器 1、Tomcat 2、Jetty 3、Undertow 二、什么是HTTP/2协议 1、定义 2、特性 3、优点 4、与HTTP/1.1的区别 三、集成Web服务器并开启HTTP/2协议 1、生成证书 2、新建springboot项目 3、集成Web服务器 3.1 集成Tomcat 3.2 集成Jetty 3.3 集成…

《Python实战进阶》专栏 No 5:GraphQL vs RESTful API 对比与实现

《Python实战进阶》专栏包括68集&#xff0c;每一集聚焦一个中高级技术知识点&#xff0c;涵盖Python在Web开发、数据处理、自动化、机器学习、并发编程等领域的应用&#xff0c;系统梳理Python开发者的知识集。本集的主题为&#xff1a; No4 : GraphQL vs RESTful API 对比与实…

MYSQL 5.7数据库,关于1067报错 invalid default value for,解决方法!

???作者&#xff1a; 米罗学长 ???个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 ???各类成品java毕设 。javaweb&#xff0c;ssm&#xff0c;springboot&#xff0c;mysql等项目&#xff0c;源码丰富&#xff0c;欢迎咨询。 ???…

【Linux基础】Linux下的C编程指南

目录 一、前言 二、Vim的使用 2.1 普通模式 2.2 插入模式 2.3 命令行模式 2.4 可视模式 三、GCC编译器 3.1 预处理阶段 3.2 编译阶段 3.3 汇编阶段 3.4 链接阶段 3.5 静态库和动态库 四、Gdb调试器 五、总结 一、前言 在Linux环境下使用C语言进行编程是一项基础且…

浅谈HTTP及HTTPS协议

1.什么是HTTP&#xff1f; HTTP全称是超文本传输协议&#xff0c;是一种基于TCP协议的应用非常广泛的应用层协议。 1.1常见应用场景 一.浏览器与服务器之间的交互。 二.手机和服务器之间通信。 三。多个服务器之间的通信。 2.HTTP请求详解 2.1请求报文格式 我们首先看一下…

Pytest自定义测试用例执行顺序

文章目录 1.前言2.pytest默认执行顺序3.pytest自定义执行顺序 1.前言 在pytest中&#xff0c;我们可能需要自定义测试用例的执行顺序&#xff0c;例如登陆前需要先注册&#xff0c;这个时候就需要先执行注册的测试用例再执行登录的测试用例。 本文主要讲解pytest的默认执行顺序…

人大金仓KCA | 用户与角色

人大金仓KCA | 用户与角色 一、知识预备1. 用户和角色 二、具体实施1. 用户管理-命令行1.1 创建和修改用户1.2 修改用户密码1.3 修改用户的并发连接数1.4 修改用户的密码有效期 2.用户管理-EasyKStudio2.1 创建和修改用户2.2 修改用户密码2.3 修改用户的并发连接数2.4 修改用户…

【Azure 架构师学习笔记】- Azure Databricks (12) -- Medallion Architecture简介

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (11) – UC搭建 前言 使用ADB 或者数据湖&#xff0c;基本上绕不开一个架构“Medallion”&#xff0c; 它使得数据管理更为简单有效。ADB 通过…

智能证件照处理器(深度学习)

功能说明:支持常见证件照尺寸(一寸、二寸、护照等) 智能背景去除(使用深度学习模型)自定义背景颜色选择自动调整尺寸并保持比例实时预览处理效果注意:整合rembg进行抠图,使用Pillow处理图像缩放和背景替换,定义常见证件照尺寸,并提供用户交互选项。首次运行时会自动下…

C++-第十三章:红黑树

目录 第一节&#xff1a;红黑树的特征 第二节&#xff1a;实现思路 2-1.插入 2-1-1.unc为红 2-1-2.cur为par的左子树&#xff0c;且par为gra的左子树(cur在最左边) 2-1-2-1.unc不存在 2-1-2-2.unc为黑 2-1-3.cur为par的右子树&#xff0c;且par为gra的右子树(cur在最右侧) 2-…