首页 > 其他分享 >用户登录状态

用户登录状态

时间:2023-02-07 00:45:15浏览次数:42  
标签:状态 登录 jwt app ctx 用户 token user router

http是一个无状态协议,比如无法识别用户,保持登录状态

服务器识别用户

使用session识别用户


index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>首页</h1>
    <form action="/logout" method="post">
        <button>登出</button>
    </form>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="/login" method="post">
        <input type="text" name="username" placeholder="用户名">
        <input type="password" name="password" placeholder="密码">
        <button>登录</button>
    </form>
</body>
</html>

home.js

'use strict';

const { Controller } = require('egg');

class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    if(this.ctx.session.user){
      await ctx.render("index");
    }else{
      ctx.redirect("/login");
    }
  }

  async login(){
    await this.ctx.render("login");
  }

  async doLogin(){
    let username = this.ctx.request.body.username;
    let password = this.ctx.request.body.password;
    if(username == "admin" && password == "123456"){
      this.ctx.session.user = username;
      this.ctx.redirect("/");
    }else{
      this.ctx.redirect("/login");
    }
  }

  async logout(){
    this.ctx.session.user = "";
    this.ctx.redirect("/login");
  }
}

module.exports = HomeController;

router.js

'use strict';//严格模式

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => { 
  const { router, controller } = app;
  router.get('/', controller.home.index);
  router.get('/login', controller.home.login);
  router.post('/login', controller.home.doLogin);
  router.post('/logout', controller.home.Logout);
};

post拦截记得要去掉

使用jwt(json web token)识别用户



config.default.js

生成token和校验token

async index(){
        //这段用于教学
        let user = {
            username:"admin"
        }//json对象
        /*egg-jwt插件导入后能引用this.app里的jwt属性来获取jwt对象
        它的sign方法能将里面的对象签名以实现加密*/
        //用户登录服务器会生成一个token,然后把token发送给客户端
       let token = this.app.jwt.sign(user,this.app.config.jwt.secret);//对象,密钥
        /*    this.ctx.body = token;
        得到一串很长的字符串
        eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
        eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjc1Njg5MDUxfQ.
        eC0L0YRrxTYKrpP3uNUJ0aaPIs8Sl4ZMcZhmDoKDKp4
        */

        try{
            //用户再次请求数据的时候都要带着生成的token给服务器校验
            let decode = this.app.jwt.verify(token,this.app.config.jwt.secret);
            /*解密token以校验,如果校验得出来就说明用户登录验证成功。
            如果token是伪造的,则会跳转到报错页
            如果不想跳转报错,想给反馈,就用捕获异常*/
            /*this.ctx.body = decode;//{"username":"admin","iat":1675689453}
            前面是token的信息,后面是时间戳
            */
        }catch(e){
            this.ctx.body = "token验证失败"
        }
    }

功能实现

以前后端分离的形式
后端egg

先行配置jwt、cors插件
jwt.js

const Controller = require("egg").Controller

class JwtController extends Controller {
    async index(){
        this.ctx.body = "hi,egg";
    }

    async doLogin(){//处理用户登录,验证成功就发个token
        let user = this.ctx.request.body.user;//前端传过来的user,包含username和password属性
        if(user.username === "admin" && user.password === "123456"){
            let user_jwt = {userjwt:user.username};//用user.username来签名生成token
            let token = this.app.jwt.sign(user_jwt,this.app.config.jwt.secret);
            this.ctx.body = {
                code:20000,
                token:token
            }//验证成功就给个响应,code和token是自己定义的,像msg那样
        }else{//登录失败的响应
            this.ctx.body = {
                code:40000,
                msg:"用户名或密码错误"
            }
        }
    }

    async getMessage(){//前端向后台获取信息时校验token
        let token = this.ctx.request.header.token;//获取请求头里的token属性的值
        try{
            //用户再次请求数据的时候都要带着生成的token给服务器校验
            let decode = this.app.jwt.verify(token,this.app.config.jwt.secret);
            /*解密token以校验,如果校验得出来就说明用户登录验证成功。
            如果token是伪造的,则会跳转到报错页
            如果不想跳转报错,想给反馈,就用捕获异常*/
            /*this.ctx.body = decode;//{"username":"admin","iat":1675689453}
            前面是token的信息,后面是时间戳
            */
           this.ctx.body = "hello jwt";
        }catch(e){
            this.ctx.body = "token验证失败"
        }
    }
}

module.exports = JwtController

router.js

'use strict';//严格模式

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => { 
  const { router, controller } = app;
  router.get('/', controller.home.index);
  router.get('/login', controller.home.login);
  router.post('/login', controller.home.doLogin);
  router.post('/logout', controller.home.logout);
  router.get('/jwt', controller.jwt.index);
  router.post('/jwtlogin', controller.jwt.doLogin);//处理前端/login提交的表单
  router.get('/jwtmessage', controller.jwt.getMessage);//处理响应数据
};

前端vue

Login.vue

<template>
    <h1>登录</h1>
    <form @submit.prevent="doLogin">
        <input type="text" name="username" v-model="user.username" placeholder="用户名">
        <input type="password" name="password" v-model="user.password" placeholder="密码">
        <button>登录</button>
    </form>
</template>

<script>
import axios from "axios";
export default {
    data(){
        return {
            user:{
                username:"",
                password:""
            }
        }
    },
    methods:{
        doLogin(){
            axios.post("http://127.0.0.1:7001/jwtlogin",{user:this.user})//跨域发送user对象给后台负责登录验证的地址/jwtlogin
            .then((res)=>{
                if(res.data.code === 20000){//后台响应的数据里有个code字段,值为20000则成功
                    localStorage.setItem("token",res.data.token);//把响应的token值存在本地储存的token字段中
                    console.log(res.data.token)
                    this.$router.push("/");
                }
            })
            
        }
    }
}
</script>

Home.vue

<template>
    <h1>首页</h1>
    <button @click="getMessage">获取数据</button>
    <button @click="logout">登出</button>
</template>

<script>
import axios from 'axios';
export default {
    methods:{
        getMessage(){
            let token = localStorage.getItem("token");//从本地存储中拿到token
            axios.get("http://127.0.0.1:7001/jwtmessage",{headers:{token:token}}).then((res)=>{
                /*axios的get请求,它的第二个参数能设置请求头响应头之类的信息。
                headers代表的是请求头,headers:{token:token}的意思是
                在请求头中设置一个字段为token(:左边)的属性,字段的值为token(:右边)
                如果是post请求,第二个参数是数据,第三个才算请求头*/
            })
        },
        logout(){
            localStorage.setItem("token","");
            location.reload();//js的方法,能自动刷新页面
        }
    }
}
</script>

App.vue

<template>
  <router-view></router-view><!--用router-view占位,换页后显示的组件放在这里-->
</template>

<script>

export default {
  name: 'App',
  
}
</script>

router.js

import { createRouter,createWebHashHistory } from "vue-router";//引入创建路由的方法和哈希模式
import Home from "./components/Home.vue"//要加上.vue不让显示不出来
import Login from "./components/Login.vue"

const  router = createRouter({
    history:createWebHashHistory(),//路由模式
    routes:[//配置路由
        {
            path:"/",//首页
            component:Home//跳转到Home组件
        },
        {
            path:"/login",
            component:Login
        }
    ]
});//创建路由

router.beforeEach((to,from,next) => {
    //只有存在token时才能跳转到内容页
    //localStorage的getItem方法能根据数据名获取它的值
    let token = localStorage.getItem("token");
    if(token || to.path === "/login"){//有token或者访问的是登录页
        next();
    }else {
        next("/login");//否则让路由跳转到登录页
    }
})

export default router;

main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import router from './router.js'//引入router

const app = createApp(App)
app.use(router);
app.mount('#app')

用户携带token的方式,把token放到请求头requestHeader中。后台也由此校验

结果

点击登录

点击获取数据

点击登出

标签:状态,登录,jwt,app,ctx,用户,token,user,router
From: https://www.cnblogs.com/ben10044/p/17097100.html

相关文章

  • pandas 用户数据分析
    importpandasaspdimportnumpyasnpfrommatplotlibimportpyplotasplt"""第一部分:数据类型处理数据加载字段含义:user_id:用户IDo......
  • 2. Linux用户管理
    1.用户管理1.1用户信息相关文件​/etc/passwd​​:存储用户的基本信息​root:x:0:0:root:/root:/bin/bash​​用户名:密码占位符:UID:GID:描述:​用户名密码:都是​​x​​,......
  • 获取安卓内存状态
    packagecom.itheiima28.memorydemo;importjava.io.File;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Environment;importandroid.os.Stat......
  • 保存数据到手机内存(QQ登录保存密码)
    点击记住密码,保存账号密码。1.获取各数据的对象2.判断记住密码是否被选中,如果被选中,存起来3.登录成功显示界面:<spanstyle="font-size:14px;"><LinearLayoutxmlns:andro......
  • 保存数据到手机内存代码优化(QQ登录保存密码)
    packagecom.itheima28.qqlogin;importjava.io.File;importjava.util.Map;importcom.itheima28.qqlogin.utils.Utils;importcom.itheima28.qqlogin.utils.UtilsOfSDCard......
  • root用户远程连接RocklyLinux9
    由于RocklyLinux9默认是拒绝Root用户22端口远程访问,所以需要进行调整1、登录服务器2、进入目录vi/etc/ssh/sshd_config3、修改PermitRootLoginprohibit-password为P......
  • Abp vnext 6.0手机号验证码登录
    abpvnext6.0之后官方替换了原来的ids4,采用了openIddict的oauth认证框架。最近有一个需求是要做手机号+短信验证码登录,故需要对openiddict的授权流程进行扩展,下面记录流程......
  • 禁用root账户登录,新建用户权限与root一致
    1、使用管理员登录系统2、修改文件vi/etc/passwd修改root❌0:0:root:/root:/bin/bash为root❌0:0:root:/root:/sbin/nologin3、新建用户adduseradmin4、修改......
  • vue+element ui实现页面平滑滚动,滚动监听(导航栏根据内容块滑动改变状态)
    一、效果图二、点击导航栏页面平滑滚动1.首先在子组件设置锚点如图中给与导航栏对应的四个div设置锚点id2.在子组件编写滚动方法监听路由的变化实现fetchData函数可以看到......
  • 理解vuex -- vue的状态管理模式
    [b]vuex是什么?[/b]先引用vuex官网的话:[quote]Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以......