authentication(验证)和authorization(授权)都是针对Auth.User
协议。验证是获知“他是谁”,授权是告诉“他能做什么”。Vapor拥有一套可扩展的身份验证系统,并且你可以将其作为复杂的授权的基础。
github上的验证demo
User Protocol
任何类型都可以遵守Auth.User
协议,但是一般都是用在Fluent Model
上。
import Vapor
import Auth
final class User: Model {
var id: Node?
var name: String
...
}
extension User: Auth.User {
static func authenticate(credentials: Credentials) throws -> Auth.User {
}
static func register(credentials: Credentials) throws -> Auth.User {
}
}
上面是一个遵守Author.User
协议的User
类。注意我们的User
类和协议的User
同名,所以我们使用Author
作为前缀将其区分开。
Authenticate
当一组凭据传递给静态authenticate
方法时,如果返回了匹配的用户,则通过验证。
Credentials
protocol Credentials { }
Credentials
协议是任何类型可以遵守的空协议。 这为您的身份验证model提供了极大的灵活性,但也要求您正确处理不支持的凭据类型。
Access Token
AccessToken
是最简单的凭据类型之一,它包括一个String
token,用于用户验证。
下面是如何支持访问Token类型:
static func authenticate(credentials: Credentials) throws -> Auth.User {
switch credentials {
case let accessToken as AccessToken:
guard let user = try User.query().filter("access_token", accessToken.string).first() else {
throw Abort.custom(status: .forbidden, message: "Invalid access token.")
}
return user
default:
let type = type(of: credentials)
throw Abort.custom(status: .forbidden, message: "Unsupported credential type: \(type).")
}
}
第一步是将凭证(credentials)类型转为我们支持的凭证类型,上面是转为了AccessToken
。如果access token不存在,则通知客户端凭证无效。
一旦我们获取了用户凭证(access token),就可以用它开查询与之匹配的用户(user model)。当然这是在表或者collection中存储了access token字段。你也可以在其他地方存储access token。
一旦我们找到与access token匹配的用户,只需返回它。
Identifier
Vapor内部使用Identifier
凭据类型来查找用户。这部分可以Request
部分学习。
Register
register
方法与authenticate
方法类似,都是使用凭证,不过register
方法不是存数据存储中提取user,而是一个创建用户的便捷方式。你不需要必须通过此方法注册用户。
Example
下面是一个支持多种凭据类型的示例:
extension User: Auth.User {
static func authenticate(credentials: Credentials) throws -> Auth.User {
let user: User?
switch credentials {
case let id as Identifier:
user = try User.find(id.id)
case let accessToken as AccessToken:
user = try User.query().filter("access_token", accessToken.string).first()
case let apiKey as APIKey:
user = try User.query().filter("email", apiKey.id).filter("password", apiKey.secret).first()
default:
throw Abort.custom(status: .badRequest, message: "Invalid credentials.")
}
guard let u = user else {
throw Abort.custom(status: .badRequest, message: "User not found.")
}
return u
}
static func register(credentials: Credentials) throws -> Auth.User {
...
}
}
Note:尽量不要存储密码,如果你必须这样做,一定要进行哈希化或者加密。