Files
ShaFaFanXin/管理后台/登录逻辑说明.md

4.0 KiB
Raw Blame History

登录接口逻辑说明

问题描述

原先的实现中,登录失败时后端会抛出 UnauthorizedExceptionHTTP 401前端响应拦截器收到 401 后会自动清空 token 并跳转到登录页,这在登录页面本身会造成逻辑混乱。

解决方案

1. 后端修改 (后端/src/auth/auth.controller.ts)

修改前

async login(@Body() loginDto: LoginDto): Promise<any> {
  const result = await this.authService.login(loginDto);
  return { code: 0, message: 'success', data: result };
}
  • 如果 auth.service 抛出 UnauthorizedException,会直接返回 HTTP 401 状态码

修改后

async login(@Body() loginDto: LoginDto): Promise<any> {
  try {
    const result = await this.authService.login(loginDto);
    return {
      code: 0,
      message: '登录成功',
      data: result,
    };
  } catch (error) {
    // 登录失败返回统一格式,不抛出 HTTP 异常
    return {
      code: 401,
      message: error.message || '用户名或密码错误',
      data: null,
    };
  }
}

关键变化

  • HTTP 状态码始终为 200
  • 通过响应体的 code 字段区分成功0和失败401
  • 错误信息通过 message 字段返回

2. 前端修改 (管理后台/src/utils/request.ts)

修改前

if (res.code !== 0 && res.code !== 200) {
  ElMessage.error(res.message || '请求失败')
  
  if (res.code === 401) {
    const userStore = useUserStore()
    userStore.logout()
    router.push('/login')
  }
  
  return Promise.reject(new Error(res.message || '请求失败'))
}
  • 所有 401 都会跳转登录页

修改后

if (res.code !== 0 && res.code !== 200) {
  const isLoginRequest = response.config.url?.includes('/auth/login')
  
  if (res.code === 401 && !isLoginRequest) {
    ElMessage.error('登录已过期,请重新登录')
    const userStore = useUserStore()
    userStore.logout()
    router.push('/login')
  } else if (!isLoginRequest) {
    ElMessage.error(res.message || '请求失败')
  }
  
  return Promise.reject(new Error(res.message || '请求失败'))
}

关键变化

  • 区分登录请求和其他请求
  • 登录接口的 401 不会触发自动跳转
  • 登录接口的错误消息不在拦截器中显示(由登录页面处理)

3. 前端登录页面 (管理后台/src/views/login/index.vue)

保持原有的错误处理逻辑:

try {
  await userStore.login(loginForm.username, loginForm.password)
  ElMessage.success('登录成功')
  router.push('/')
} catch (error: any) {
  const errorMessage = error.message || '登录失败,请检查用户名和密码'
  ElMessage.error(errorMessage)
}

关键点

  • 登录页面自己处理并显示错误信息
  • 错误消息来自后端返回的 message 字段

最终效果

登录成功

请求: POST /api/auth/login
响应: { code: 0, message: '登录成功', data: { user: {...}, access_token: '...', refresh_token: '...' } }
结果: 显示"登录成功",跳转到首页

登录失败(用户名或密码错误)

请求: POST /api/auth/login
响应: { code: 401, message: '用户名或密码错误', data: null }
结果: 显示"用户名或密码错误",停留在登录页

登录失败(账户被禁用)

请求: POST /api/auth/login
响应: { code: 401, message: '账户已被禁用,请联系管理员', data: null }
结果: 显示"账户已被禁用,请联系管理员",停留在登录页

其他接口 Token 过期

请求: GET /api/case/list
响应: { code: 401, message: 'Unauthorized', data: null }
结果: 显示"登录已过期,请重新登录",清空 token跳转到登录页

总结

这个修改确保了:

  1. 登录接口:失败时返回友好的错误信息,不会触发自动跳转
  2. 其他接口Token 过期时自动清理状态并跳转到登录页
  3. 用户体验:错误提示清晰准确,不会出现重复提示或循环跳转