Part5-前后端登录注册实现

一、前端登录注册界面布局

借助Antd的 表单组件(登录框) 可以快速实现。

二、注册接口开发

1、JWT简介

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。

注册必然要产生token,这是用户的登录凭证。JWT的官网地址:https://jwt.io/

一个JWT实际上就是一个字符串,它由三部分组成,头部载荷签名

2、Koa中生成token

a. 安装

$ npm i jsonwebtoken -S

b. 生成token

const jwt = require('jsonwebtoken');

// 根据username和password生成token
let token=jwt.sign(
    {username,password},    // 携带信息
    'zhaowenxian',          // 秘钥
    {expiresIn:'1h'}        // 有效期:1h一小时
)

expiresIn:以秒表示或描述时间跨度zeit/ms的字符串。如60,"2 days","10h","7d",Expiration time,过期时间

更多字段可参考:https://blog.csdn.net/weixin_34314962/article/details/89057225

3、鉴权

已经产生了token,前端调用接口时传过来的token,就需要后端进行比较,我们称之为 鉴权

//鉴权
const auth=async (ctx,next)=>{
    try{
        // let result = jwt.verify(token,'zhaowenxian')//解构
        jwt.verify(token,'zhaowenxian')//验证
        
    }catch(err){
        //try中报错就会走catch,
        ctx.body={
            code:500,
            message: "token无效或登录已过期"
        }
        return;
    }
    await next();//放行函数,继续往下走
}
router.get('/api/edit',auth,async (ctx,next)=>{//在参数里执行
//需要权限才加auth,没有next()放行函数,不会往下走
    ctx.body={
        code:200
    }
})

三、Koa获取请求体

Koa获取请求体的方式是使用第三方插件:

$ npm i koa-bodyparser

然后在 app.js 中直接引入并调用:

const bodyParser = require('koa-bodyparser');

// 调用router中间件
app.use(bodyParser());	// bodyParser
app.use(router.routes(), router.allowedMethods());

四、Axios+TS的请求封装

前端React管理系统项目使用Axios进行请求,封装的过程结合ts使用。

src 下创建 request/api.tsrequest/request.ts

1、封装request

import axios from 'axios'

// 配置项接口
interface AxiosOption {
    baseURL: string;
    timeout: number;
}

// 配置项
const axiosOption: AxiosOption = {
    baseURL: 'http://localhost:9000/manage',
    timeout: 5000
}

// 创建一个单例
const instance = axios.create(axiosOption);

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
  let token = localStorage.getItem("x-auth-token");
  if (token) {
    config.headers = {
      "x-auth-token": token
    }
  }
  return config;
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error);
});

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
  // 对响应数据做点什么
  return response.data;
}, function (error) {
  // 对响应错误做点什么
  return Promise.reject(error);
});

export default instance;

2、导出api

api.ts 中:

import request from './request'

interface IRegisterParams {
    username: string | number;
    password: string | number;
}

// 注册
export const RegisterApi = (params: IRegisterParams) => request.post('/register', params)

3、调用api

import { RegisterApi } from "request/api";
import { message } from 'antd';

interface IValues {
    username: string | number;
    password: string | number;
}

// 执行注册
const onFinish = (values: IValues) => {
    RegisterApi(values).then((res: any) => {
        if(res.errCode===0){
            message.success(res.message);
        }else{
            message.error(res.message);
        }
    });
};

五、接口文档

小幺鸡(docway)平台:http://xiaoyaoji.cn/

六、React Redux管理用户信息

首先,安装redux与react-redux:

$ npm i redux react-redux

1、reducer

在 src 下新建 store/reducer.ts

interface IState {
  username: string;
  player: string;
  avatar: string;
}

// 定义默认数据
const defaultState: IState = {
  username: "",
  player: "",
  avatar: "",
};

interface IAction {
  type: string;
  value?: unknown;
}

// eslint-disable-next-line
export default (state = defaultState, action: IAction) => {
  let newState = JSON.parse(JSON.stringify(state));
  switch (action.type) {
    case "ChangeUsername":	// 修改名称
      newState.username = action.value;
      break;
    case "ChangePlayer":	// 修改角色
      newState.player = action.value;
      break;
    case "ChangeAvatar": 	// 修改头像
      newState.avatar = action.value;
      break;
    default:
      break;
  }
  return newState;
};

2、store

在 src 下新建 store/index.ts

import { createStore } from "redux";
import reducer from './reducer'

const store = createStore(reducer)
export default store;

3、调用

组件中使用connect进行调用:

import { connect } from "react-redux";

const mapStateToProps = (state: IState) => {
  return {
    userName: state.username,
    avatar: state.avatar,
  };
};

const mapDispatchToProps = (dispatch: any) => {
  return {
    // 修改react-redux的用户名
    changeUsername<T>(value: T):void{
      dispatch({type: "ChangeUsername", value})
    },
    // 修改react-redux的密码
    changePlayer<T>(value: T):void{
      dispatch({type: "ChangePlayer", value})
    },
    // 修改react-redux的头像
    changeAvatar<T>(value: T):void{
      dispatch({type: "ChangeAvatar", value})
    },
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(组件名称);

七、React环境变量配置

React的环境变量配置可以通过.env文件进行配置,建议使用插件配合。

1、cross-env插件

$ npm install --save-dev cross-env

然后打开 config/env.js,搜索 getClientEnvironment ,在其中添加:

function getClientEnvironment(publicUrl) {
  const raw = Object.keys(process.env)
    .filter(key => REACT_APP.test(key))
    .reduce(
      (env, key) => {
        env[key] = process.env[key];
        return env;
      },
      {
        ...
        SERVER_HOST_PORT: process.env.SERVER_HOST_PORT,  // 添加这一句
        SERVER_HOST: process.env.SERVER_HOST  // 添加这一句
      }
    );
  return { raw, stringified };
}

然后在项目根目录新建两个文件:

.env 开发环境:

NODE_ENV = development
SERVER_HOST_PORT = http://localhost:9000/manage
SERVER_HOST = http://localhost:9000

.env.production 生产环境:

NODE_ENV = production
SERVER_HOST_PORT = 线上真实接口地址
SERVER_HOST = 线上真实项目

2、项目运行、测试与打包

当你运行 npm start 时,它总是等于 'development' ,

当你运行 npm test 它总是等于 'test' ,

当你运行 npm run build 来生成一个生产 bundle(包) 时,它总是等于 'production'

最后更新于