我已经创建了一个login
端点:
try LoginUserDTO.validate(content: request)
let loginUserDTO = try request.content.decode(LoginUserDTO.self)
let userService = UserService(database: request.db)
let user = try await userService.get(by: loginUserDTO.email)
if (try user.verify(password: loginUserDTO.password)) == false {
throw Abort(.unauthorized)
}
let userToken = UserToken(accessToken: generateToken(),
refreshToken: generateToken(),
accessTokenExpirationDate: generateAccessTokenExpirationDate(),
refreshTokenExpirationDate: generateRefreshTokenExpirationDate(),
user: user)
try await userToken.create(on: request.db)
request.auth.login(user)
return ClientTokenReponse(accessToken: userToken.accessToken,
refreshToken: userToken.refreshToken,
accessTokenExpirationDate: userToken.accessTokenExpirationDate,
refreshTokenExpirationDate: userToken.refreshTokenExpirationDate)
检查用户凭据,创建并返回令牌。现在我想测试我的UserAuthenticator
是否工作:
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)
}
// TODO: Add additional check if accessToken is not expired yet!
if bearer.token == userToken.accessToken {
request.auth.login(loginUser.toUser())
}
}
}
所以我加了:
let protected = app.grouped([User.authenticator()])
protected.post("me") { request async throws -> String in
let user = try? request.auth.require(User.self)
if user != nil {
return "yes"
} else {
return "no"
}
}
User显然总是nil。似乎我的UserAuthenticator
中的代码甚至从未执行过。我做错了什么?
好了,做了一些改变,突然它工作了:
改变了我的authenticate()
方法,因为它期望在请求中传递电子邮件和密码(这是无稽之谈,因为承载在标头中发送:))。
func authenticate(bearer: BearerAuthorization, for request: Request) async throws {
guard let userToken = try await UserToken.query(on: request.db)
.join(User.self, on: UserToken.$user.$id == User.$id)
.filter(.$accessToken == bearer.token)
.first()
else {
throw Abort(.unauthorized)
}
let user = try userToken.joined(User.self)
// TODO: Add check if accessToken is not expired yet!
if bearer.token == userToken.accessToken {
request.auth.login(User(email: user.email, passwordHash: user.passwordHash))
}
}
另一个是我如何在routes
文件中使用UserAuthenticator
:
使用:
let protected = app.grouped(UserAuthenticator())
代替:
let protected = app.grouped([User.authenticator()])
工作!