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

1.登录页面

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

javascript 复制代码
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

javascript 复制代码
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连 谢谢!! 下篇 咱实现导航栏和 修改个人信息

相关推荐
福兮说6 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理7 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
小呆呆6668 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
凤城老人8 小时前
从 PyQt6 到 Electron:给 Edge TTS 做一个“多角色配音机“的踩坑手记
javascript·typescript·electron
Dovis(誓平步青云)8 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan8 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_9 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒9 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端
广州华水科技9 小时前
大坝安全监测解决方案:单北斗GNSS形变监测系统应用与维护
前端
星光开发者10 小时前
基于决策树随机森林算法的小说推荐系统的设计与实现-计算机毕设【课程设计】78485
vue.js·算法·微信小程序·django·php·课程设计·express