六 【实战】 element-plus-admin + 串联登录接口

457 阅读3分钟

一 将前端代码跑起来。

导入代码 。 github.com/hsiangleev/…

npm install
npm run dev

访问 http://localhost:3002

image.png

二 装个软件.hbuilderx

www.dcloud.io/hbuilderx.h…

三 分析登录接口。

3.1 登录接口.

api xxx.com/api/User/lo…

method : postjson

request

  {username: "admin", password: "admin"}

response

{"Code":200,"Msg":"登陆成功","Data":"token_value"}

失败
{"Code":401,"Msg":"用户名或密码错误","Data":""}

3.2 getRoute 获取菜单 .

api xxx.com/api/User/ge…

method : get

request

header:  Access-Token: token_value

Access-Token:token

{
    "Code": 200,
    "Msg": "",
    "Data": [
        {
            "id": 2,
            "parentId": 0,
            "name": "Project",
            "path": "/Project",
            "component": "Layout",
            "redirect": "/Project/ProjectList",
            "meta": {
                "title": "项目管理",
                "icon": "el-icon-phone",
                "permission": []
            }
        },
        {
            "id": 20,
            "parentId": 2,
            "name": "ProjectList",
            "path": "/Project/ProjectList",
            "component": "ProjectList",
            "meta": {
                "title": "项目列表",
                "icon": "el-icon-goods",
                "permission": []
            }
        },
        {
            "id": 21,
            "parentId": 2,
            "name": "ProjectDetail",
            "path": "/Project/ProjectDetail/:projName",
            "component": "ProjectDetail",
            "meta": {
                "title": "项目详情",
                "icon": "el-icon-question",
                "activeMenu": "/Project/ProjectList",
                "hidden": true,
                "permission": []
            }
        },
        {
            "id": 22,
            "parentId": 2,
            "name": "ProjectImport",
            "path": "/Project/ProjectImport",
            "component": "ProjectImport",
            "meta": {
                "title": "项目导入",
                "icon": "el-icon-help",
                "permission": []
            }
        },
        {
            "id": 3,
            "parentId": 0,
            "name": "Nav",
            "path": "/Nav",
            "component": "Layout",
            "redirect": "/Nav/SecondNav/ThirdNav",
            "meta": {
                "title": "多级导航",
                "icon": "el-icon-picture",
                "permission": []
            }
        },
        {
            "id": 30,
            "parentId": 3,
            "name": "SecondNav",
            "path": "/Nav/SecondNav",
            "redirect": "/Nav/SecondNav/ThirdNav",
            "component": "SecondNav",
            "meta": {
                "title": "二级导航",
                "icon": "el-icon-camera",
                "alwaysShow": true,
                "permission": []
            }
        },
        {
            "id": 300,
            "parentId": 30,
            "name": "ThirdNav",
            "path": "/Nav/SecondNav/ThirdNav",
            "component": "ThirdNav",
            "meta": {
                "title": "三级导航",
                "icon": "el-icon-platform",
                "permission": []
            }
        },
        {
            "id": 31,
            "parentId": 3,
            "name": "SecondText",
            "path": "/Nav/SecondText",
            "redirect": "/Nav/SecondText/ThirdText",
            "component": "SecondText",
            "meta": {
                "title": "二级文本",
                "icon": "el-icon-opportunity",
                "alwaysShow": true,
                "permission": []
            }
        },
        {
            "id": 310,
            "parentId": 31,
            "name": "ThirdText",
            "path": "/Nav/SecondText/ThirdText",
            "component": "ThirdText",
            "meta": {
                "title": "三级文本",
                "icon": "el-icon-menu",
                "permission": []
            }
        },
        {
            "id": 4,
            "parentId": 0,
            "name": "Components",
            "path": "/Components",
            "component": "Layout",
            "redirect": "/Components/OpenWindowTest",
            "meta": {
                "title": "组件测试",
                "icon": "el-icon-phone",
                "permission": []
            }
        },
        {
            "id": 40,
            "parentId": 4,
            "name": "OpenWindowTest",
            "path": "/Components/OpenWindowTest",
            "component": "OpenWindowTest",
            "meta": {
                "title": "选择页",
                "icon": "el-icon-goods",
                "permission": []
            }
        },
        {
            "id": 41,
            "parentId": 4,
            "name": "CardListTest",
            "path": "/Components/CardListTest",
            "component": "CardListTest",
            "meta": {
                "title": "卡片列表",
                "icon": "el-icon-question-filled",
                "permission": []
            }
        },
        {
            "id": 42,
            "parentId": 4,
            "name": "TableSearchTest",
            "path": "/Components/TableSearchTest",
            "component": "TableSearchTest",
            "meta": {
                "title": "表格搜索",
                "icon": "el-icon-question-filled",
                "permission": []
            }
        },
        {
            "id": 43,
            "parentId": 4,
            "name": "ListTest",
            "path": "/Components/ListTest",
            "component": "ListTest",
            "meta": {
                "title": "标签页列表",
                "icon": "el-icon-question-filled",
                "permission": []
            }
        },
        {
            "id": 5,
            "parentId": 0,
            "name": "Permission",
            "path": "/Permission",
            "component": "Layout",
            "redirect": "/Permission/Directive",
            "meta": {
                "title": "权限管理",
                "icon": "el-icon-phone",
                "alwaysShow": true,
                "permission": []
            }
        },
        {
            "id": 50,
            "parentId": 5,
            "name": "Directive",
            "path": "/Permission/Directive",
            "component": "Directive",
            "meta": {
                "title": "指令管理",
                "icon": "el-icon-goods",
                "permission": [
                    "add",
                    "update",
                    "remove"
                ]
            }
        }
    ]
}

得到菜单 。

3.3 获取用户信息.

api xxx.com/api/User/ge…

method : get

request

header:  Access-Token: token_value

response

{"Code":200,"Msg":"",
    "Data":
    {"name":"admin","role":["admin"]}
}

4 接口base_url 更换。

一波查找后,修改

const request = axios.create({
    // API 请求的默认前缀
    baseURL: import.meta.env.VUE_APP_API_BASE_URL as string | undefined,
    timeout: 60000 // 请求超时时间
})

将配置改一下

package.json

  "scripts": {
    "dev": "vite --mode development"
    ...
  }

新建 .env.development

VITE_BASE_URL=http://127.0.0.1

修改 utils/request.ts

// 创建 axios 实例
const request = axios.create({
    // API 请求的默认前缀
    baseURL: import.meta.env.VITE_BASE_URL as string | undefined,
    timeout: 60000 // 请求超时时间
})

修改后端代码 使其符合需求 。

{"Code":401,"Msg":"用户名或密码错误","Data":""} 碰到hyperf 的恶心问题,route 不支持大写字母。 折中一下,后端改为

/api/user/login

前端进行修改 src/api/layout/index.ts

import request from '/@/utils/request'
import { AxiosResponse } from 'axios'
import { IMenubarList } from '/@/type/store/layout'

const api = {
    login: '/api/user/login',
    getUser: '/api/user/get-user',
    getRouterList: '/api/user/get-route',
    publickey: '/api/User/public-key'
}

又产生跨域问题。

Access to XMLHttpRequest at 'http://127.0.0.1/api/user/login' from origin 'http://localhost:3003' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

先把问题解决掉。

docker exec -it nginx bash
apt-get update
apt-get install vim

#将这几行塞location 里面。
 add_header Access-Control-Allow-Origin *;
 add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
  add_header Access-Control-Allow-Headers 'DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') { return 204; }


重启nginx 后,再测试

image.png

新的报错

has been blocked by CORS policy: Request header field access-token is not allowed by Access-Control-Allow-Headers in preflight response.

接着改nginx 配置 ,Access-Control-Allow-Headers 加上 access-token

然后实现后端代码 。角色,菜单 先hardcode 处理。

实现效果如下。

image.png

后端代码如下。 route.php


Router::addRoute(['GET', 'HEAD'], '/api/user/get-route', 'App\Controller\MenuController::list');
Router::addRoute(['GET', 'HEAD'], '/api/user/get-user', 'App\Controller\UserController::getUser');

MenuController

<?php

declare(strict_types=1);
/**
 *
 * @Author xuxing
 * @description 机构申请接口. (apply_auto_audit 打开后,自动生效)
 */

namespace App\Controller;

use App\Constants\Enum;
use App\Constants\ErrorCode;
use App\Service\UserService;
use Hyperf\Di\Annotation\Inject;


class MenuController extends AbstractController
{



    public function list()
    {

        $menus = [
              [
                   "id"=> 2,
                    "parentId"=> 0,
                    "name"=> "Project",
                    "path"=> "/Project",
                    "component"=> "Layout",
                    "redirect"=> "/Project/ProjectList",
                    "meta"=> [
                             "title"=> "项目管理",
                        "icon"=> "el-icon-phone",
                        "permission"=> []
                    ]
              ],
              [
                  "id"=> 20,
                  "parentId"=> 2,
                  "name"=> "ProjectList",
                  "path"=> "/Project/ProjectList",
                  "component"=> "ProjectList",
                   "meta"=> [
                      "title"=> "项目管理",
                      "icon"=> "el-icon-phone",
                      "permission"=> []
                  ]
              ],
              [
                  "id"=> 22,
                  "parentId"=> 2,
                  "name"=> "ProjectImport",
                  "path"=> "/Project/ProjectImport",
                  "component"=> "ProjectImport",
                  "meta"=> [
                      "title"=> "项目导入",
                      "icon"=> "el-icon-help",
                      "permission"=> []
                  ]
              ],
        ];
        return $this->code(ErrorCode::API_SUCCESS,['Data' => $menus] );
    }
}

UserController.php

<?php

declare(strict_types=1);
/**
 *
 * @Author xuxing
 * @description 机构申请接口. (apply_auto_audit 打开后,自动生效)
 */

namespace App\Controller;
use App\Constants\ErrorCode;
use Hyperf\Di\Annotation\Inject;
use App\Service\AuthenService;

class UserController extends AbstractController
{
    #[Inject]
    protected AuthenService $authenService;

    public function getUser()
    {

        $token = $this->request->getHeader("Access-Token");
        $user = $this->authenService->getUinfo($token[0]);
        $data = ["name" => $user["tname"], "role"=>["admin"]];
        return $this->code(ErrorCode::API_SUCCESS, ['token' => $token,"user" => $user,  'Data' => $data]);
    }
}