Golang Gin jwt 实现 Ant Design Pro V5 的登录态

发布时间: 2021-05-10 13:36:17 作者: 大象笔记

Antd Design Pro 的登录逻辑在哪里

> grep "其他登录方式" -r src/
src/locales/zh-CN/pages.ts:  'pages.login.loginWith': '其他登录方式 :',
src/pages/user/Login/index.tsx:            <FormattedMessage id="pages.login.loginWith" defaultMessage="其他登录方式" />

查看

src/pages/user/Login/index.tsx

import { login } from '@/services/ant-design-pro/api';

const Login: React.FC = () => {
  ...
  const handleSubmit = async (values: API.LoginParams) => {
    setSubmitting(true);
    try {
      // 登录
      const msg = await login({ ...values, type });
      if (msg.status === 'ok') {
  ...
}

登录接口 API

src/services/ant-design-pro/api.ts

/** 登录接口 POST /api/login/account */
export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
  return request<API.LoginResult>('/api/login/account', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}

登录接口参数和返回数据结构

src/services/ant-design-pro/typings.d.ts

  type LoginParams = {
    username?: string;
    password?: string;
    autoLogin?: boolean;
    type?: string;
  };
  
  type LoginResult = {
    status?: string;
    type?: string;
    currentAuthority?: string;
  };

登录成功后如何处理登录态

https://github.com/ant-design/ant-design-pro/issues/969

登录态存储在哪里?

可能的地方:

通过登录后,关闭网页,再次打开依然是登录状态,可以排除是存在内存中的可能性。

长时间不登陆,再次登录,打开登录页,会看到右上角显示调用用户信息接口 401 错误。 说明登录态是存在 cookie, local storage 中,再次刷新,这个错误就不见了。 说明有可能针对 401 做了特殊处理,当遇到 401 时,会清空登录态,然后就不会发送请求了。

> grep 401 -r src/
src/app.tsx:    401: '用户没有权限(令牌、用户名、密码错误)。',
src/locales/en-US/request.ts:  'app.request.401': 'The user does not have permission (token, username, password error). ',
src/locales/zh-CN/request.ts:  'app.request.401': '用户没有权限(令牌、用户名、密码错误)。',

然而从代码看,并没有任何特殊处理... 只是右上角弹窗提示错误。

在 src/app.tsx 中的 getInitialState 中发现了这样一段逻辑:

这就完美解释了上面的现象。

其中有两个获取用户信息的函数:

// queryCurrentUser
import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
const currentUser = await queryCurrentUser();

// fetchUserInfo
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
const currentUser = await fetchUserInfo();

实际上都是调用同一个 HTTP API 接口拉取。

注意:这里有个大坑,会导致登录成功之后,不跳转。

v5 版本,beta 版跟正式版使用的数据结构不一致: beta 版使用的 user 接口返回的整体数据,而正式版是判断的 data 字段。日,非常不正规。浪费时间。

getInitialState 的调用时机

参考

https://umijs.org/zh-CN/plugins/plugin-initial-state

getInitialState 会在整个应用最开始执行,返回值会作为全局共享的数据。Layout 插件、Access 插件以及用户都可以通过 useModel('@@initialState') 直接获取到这份数据。

useModel 的使用

import { useModel } from 'umi';

const { initialState, loading, error, refresh, setInitialState } = useModel('@@initialState');

queryCurrentUser / currentUser

src/services/ant-design-pro/api.ts

/** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) {
  return request<API.CurrentUser>('/api/currentUser', {
    method: 'GET',
    ...(options || {}),
  });
}

request

https://beta-pro.ant.design/docs/request-cn

我们移除了默认生成的 utils/request.ts 文件

中间件 & 拦截器。在某些情况下我们需要在网络请求发出前或响应后做一些特殊处理。比如,在每次请求前在 Header 内自动加上对应的 Access Token。

参考文档,只需要在 src/app.tsx 中配置 RequestConfig 拦截器即可:

umi request 拦截器配置具体参考这里,官方文档写的配置方法不好使。。。

改造流程概要

  1. 后台增加 api/login/account 接口,校验用户名和密码。如果校验成功,返回 token
  2. 登录成功后,前端将 token 写入 local storage
  3. 前端,拦截 request,在 HTTP 头加上 token
  4. 退出登录时,删除 local storage 中的 token
  5. 后台增加 api/currentUser 接口,能返回 401
我是一名山东烟台的开发者,联系作者