Vert.x MongoDB Auth

基本术语

  • Authentication:认证
  • Authorisation:授权
  • Authority:权限
  • Permission:许可
  • Role:角色
  • User:用户
  • Token:令牌
  • Principal:凭证
  • Handler:处理器
  • Collection:集合,MongoDB专用(概念稍同Database的Table)
  • Document:文档,MongoDB专用(概念稍同Database中Row)

Vert.X中提供了一个AuthProvider的实现,它可以让你使用MongoClient针对MongoDb数据库执行认证和授权。若要在自己的项目中使用它,则需要在构建描述信息的dependencies节点中添加如下信息:

  • Maven(在pom.xml文件中)

    1. <dependency>
    2. <groupId>io.vertx</groupId>
    3. <artifactId>vertx-auth-mongo</artifactId>
    4. <version>3.2.1</version>
    5. </dependency>
  • Gradle(在build.gradle文件中)

    1. compile io.vertx:vertx-auth-mongo:3.2.1

如果要创建一个客户端实例,你首先需要一个MongoClient的实例,要知道如何创建这个实例可按照文档中的内容实施。

一旦你创建了一个MongoClient实例后,就可以按照下边的代码创建MongoAuth实例:

  1. MongoClient client = MongoClient.createShared(vertx, mongoClientConfig);
  2. JsonObject authProperties = new JsonObject();
  3. MongoAuth authProvider = MongoAuth.create(client, authProperties);

创建好上边的实例过后,你就可以使用任何AuthProvider针对MongoDB执行认证和授权功能了。

Vert.X的默认标准配置(Out Of the Box)中包含了”user”集合(Collection),用户名字段使用”username”进行存储和读取。

为了避免在”user”集合中出现重复的用户名,应该在”user”集合中给”username”添加唯一索引(Unique Index),你可以在MongoDB服务器中运行下边的片段来完成此操作:

  1. db.user.createIndex( { username: 1 }, { unique: true } )

MongoDB的特性是先查询username字段中的值是否已经存在,然后会插入一个Document,并不能作为一个原子性操作,基于这个原因你需要添加上边的唯一索引,使用了这个索引过后你的代码会尝试先插入一行数据,如果出现了重复记录则会失败。

根据你自己的需要,你同样可以使用下边的方法改变MongoDB中使用的默认集合(Collection)和列(Column)名称等信息:

Vert.X默认实现中的密码在数据库中使用了SHA-512算法加密后进行存储,之后会连接对应的salt值,这个salt值和密码存储在同一个表里。你可以调用setSaltField方法来改变存储salt值的字段名称,它的默认值是”salt”,你同样可以使用setSaltStyle来改变一些行为。通过调用getHashStrategy方法还可以读取Hash策略设置。

MongoDB中可以设置下边几种SALT的值(参考下边WARNING):

  • NO_SALT:密码就不会执行加密以明文的方式存储。
  • COLUMN:Vert.X会为每个用户创建一个”salt“值,并且存储在用户表定义的列中;
  • EXTERNAL:Vert.X仅仅将密码最终加密结果存储在数据库中,”salt“值可以在外部使用,并且可以调用setExternalSalt方法进行设置。

如果你想要重写上述行为,则你可以调用setHashStrategy方法设置新的Hash策略,并且提供变更过的Hash策略及配置信息。

!WARNING

强烈建议在设置“salt”值时候使用EXTERNAL选项。NO_SALT选项仅仅推荐在开发阶段中使用,不仅仅如此,COLUMN方式也不推荐,因为它会导致salt和密码都存储在了同一个地方!

认证

如果认证使用了默认的MongoDB实现,认证信息中用了usernamepassword字段:

  1. JsonObject authInfo = new JsonObject()
  2. .put("username", "tim")
  3. .put("password", "sausages");
  4. authProvider.authenticate(authInfo, res -> {
  5. if (res.succeeded()) {
  6. User user = res.result();
  7. } else {
  8. // Failed!
  9. }
  10. });

如果想要替换上边的usernamepassword两个默认字段名,你可以使用下边两个方法:

授权 - Permission/Role模型

尽管Vert.X自身并不要求使用特定的许可模型(它本身只是使用了不透明的字符串),但MongoDB认证中的实现使用了比较熟悉的:用户/角色/许可模型,这样在应用里你可以使用一个或者多个角色,而一个角色也可以拥有一个或者多个许可。

如果要验证一个用户是否拥有特定的许可,则要将许可信息传递到isAuthorised中:

  1. user.isAuthorised("commit_code", res -> {
  2. if (res.succeeded()) {
  3. boolean hasPermission = res.result();
  4. } else {
  5. // Failed to
  6. }
  7. });

如果要验证一个用户是否属于特定角色,则可以使用MongoDB认证前缀(MongoAuth.ROLE_PREFIX)法给角色带上前缀表示:

  1. user.isAuthorised(MongoAuth.ROLE_PREFIX + "manager", res -> {
  2. if (res.succeeded()) {
  3. boolean hasRole = res.result();
  4. } else {
  5. // Failed to
  6. }
  7. });