You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vapor中UserAuthenticator实现Bearer认证始终返回401 Unauthorized

Vapor登录接口返回401且认证器不触发问题排查

问题现象

开发登录端点时参考Bearer认证逻辑实现后,用Postman调用接口始终返回401 Unauthorized,自定义UserAuthenticator内部断点完全不会触发。

现有实现代码

自定义Bearer认证器

struct UserAuthenticator: AsyncBearerAuthenticator {

func authenticate(bearer: BearerAuthorization, for request: Request) async throws {
    typealias User = App.User

    let loginUser = try request.query.decode(LoginUserDTO.self)

    guard let user = try await User.query(on: request.db)
        .filter(\.$email == loginUser.email)
        .first(),
    let userId = user.id else {
        throw Abort(.notFound)
    }

    guard let userToken = try await UserToken.query(on: request.db)
        .filter(\.$user.$id == userId)
        .first() else {
        throw Abort(.notFound)
    }

    if bearer.token == userToken.value {
        request.auth.login(loginUser.toUser())
    }
}
}

User模型ModelAuthenticatable扩展

extension User: ModelAuthenticatable {
    static var usernameKey = \User.$email
    static var passwordHashKey = \User.$passwordHash

    func verify(password: String) throws -> Bool {
        self.passwordHash == password.generateHash(salt: salt)
    }
}

路由配置

let protected = app.grouped(UserAuthenticator())
    protected.post("login") { request async throws -> ClientTokenReponse in
        let user: User = try request.auth.require(User.self)
        return ClientTokenReponse(token: "token")
    }

排查步骤

按优先级依次检查:

  • 请求头格式校验
    Bearer认证器触发的前置条件是请求携带格式正确的Authorization头,格式必须为:
    Authorization: Bearer <有效token字符串>
    
    以下错误写法都会导致认证器直接跳过、根本不进入自定义的authenticate逻辑,直接返回401:
    • 头字段名拼写错误
    • Bearer写成小写bearer或者其他拼写
    • Bearer和后面的token之间没有半角空格、存在多余特殊字符
    • 完全没传该请求头
  • 路由中间件挂载逻辑错误
    你把/login接口挂在了Bearer认证保护的路由组下,逻辑完全倒置:
    • Bearer认证的作用是保护用户登录后、持有有效token才能访问的接口,比如获取个人信息、修改资料这类接口
    • 登录接口是用户还未获取token时访问的,本身不应该挂载Bearer认证中间件
  • 认证器逻辑设计错误
    你当前的Bearer认证器实现不符合设计规范:
    • Bearer认证的逻辑只需要从请求头拿到token值,查询token是否合法、是否关联有效用户,不需要额外从query参数解码邮箱查用户
    • 现有逻辑里查库找用户已有的token时,没有做token有效期、是否吊销等校验,存在安全隐患
  • 认证协议混用问题
    你实现的ModelAuthenticatable协议是用于用户名密码基础认证的,和当前使用的Bearer认证是两套独立的认证流程,在Bearer认证链路中不会调用该扩展的校验逻辑,不需要在当前场景实现该扩展。
  • 登录接口逻辑修正方向
    正确的登录流程应该是:
    1. 公开的/login接口接收用户提交的邮箱、密码参数
    2. 接口内根据邮箱查用户,调用密码校验方法匹配传入的明文密码
    3. 校验通过后生成新的用户token,返回给客户端
    4. 其他需要登录才能访问的接口,再挂载到Bearer认证的保护路由组下,客户端访问这些接口时才需要携带Authorization: Bearer <token>头

内容的提问来源于stack exchange,提问作者kalafun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:57:32