Vert.X中提供了一个使用 JDBCClient
的 AuthProvider
实现,它针对任何兼容JDBC的关系数据库执行认证和授权。若要在自己的项目中使用它,则需要在构建描述信息的 dependencies 节点中添加如下信息:
Maven (在 pom.xml
文件中):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-jdbc</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (在 build.gradle
文件中):
compile 'io.vertx:vertx-auth-jdbc:3.6.2'
如果要创建一个客户端实例,你首先需要一个 JDBCClient
的实例,要知道如何创建这个实例可按照文档中的内容实施。
一旦你创建了一个 JDBCClient
实例后,就可以按下边代码创建 JDBCAuth
实例:
var jdbcClient = JDBCClient.createShared(vertx, jdbcClientConfig)
var authProvider = JDBCAuth.create(vertx, jdbcClient)
创建好上边的实例过后你就可以如使用任何 AuthProvider
执行认证和授权功能了。
Vert.X的默认标准配置(Out Of the Box)中包含了某些针对认证和授权的信息查询, 如果你想要使用不同的数据库模式(Schema),
这些查询内容可以通过 setAuthenticationQuery
,
setPermissionsQuery
和
setRolesQuery
方法进行更改:
Vert.X默认实现中的密码在数据库中使用了SHA-512算法加密后进行存储,之后会连接对应的 salt
值,这个 salt
值和密码存储在同一个表里。
The basic data definition for the storage should look like this:
--
-- Take this script with a grain of salt and adapt it to your RDBMS
--
CREATE TABLE `user` (
`username` VARCHAR(255) NOT NULL,
`password` VARCHAR(255) NOT NULL,
`password_salt` VARCHAR(255) NOT NULL
);
CREATE TABLE `user_roles` (
`username` VARCHAR(255) NOT NULL,
`role` VARCHAR(255) NOT NULL
);
CREATE TABLE `roles_perms` (
`role` VARCHAR(255) NOT NULL,
`perm` VARCHAR(255) NOT NULL
);
ALTER TABLE user ADD CONSTRAINT `pk_username` PRIMARY KEY (username);
ALTER TABLE user_roles ADD CONSTRAINT `pk_user_roles` PRIMARY KEY (username, role);
ALTER TABLE roles_perms ADD CONSTRAINT `pk_roles_perms` PRIMARY KEY (role);
ALTER TABLE user_roles ADD CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES user(username);
ALTER TABLE user_roles ADD CONSTRAINT fk_roles FOREIGN KEY (role) REFERENCES roles_perms(role);
The current password hashing strategy is based on the SHA-512 algorithm. OWASP as of 2018-01-08 recommends the usage of stronger algorithms, for this case you can use the PBKDF2 strategy (OWASP recommendation).
Warning
|
If you already have a running application switching the strategies will make break your existing passwords, so you will need to migrate the passwords from one algorithm to the second. |
如果你想要重写这些行为,则可以重写
setHashStrategy
方法去修改Hash策略的设置。
Warning
|
强烈建议在存储密码时使用哈希算法加密过后保存在数据库中,这个哈希值是在创建这一行记录时基于 salt 值计算的,应用中应该使用强壮的密码算法,在存储密码时绝对不要使用明文。
|
GDPR is a regulation from the common European Union law. It overrides/supercedes national data protection laws and extents the previously existing directives. This section of the manual is by no means a thorough walkthrough of the regulation, it is just a small summary how this component adheres to the requirements. Companies not adhering to the requirements can be fined on 4% of the turnover or 20 million euro. Therefore we want to make sure that as a user of Vert.x Auth JDBC you’re are on the good track to comply.
The law defines certain terminology:
Data Subject - Person whose personal data is processed (e.g.: User)
Personal Data - Any data about an identifiable or identified person
Data Processing - Any operation (manual or automated) on personal data
Controller - The entity (company) that requests and uses the data
Processors - Any entity that processes data on behalf of a controller (e.g.: cloud service provider)
GDPR defines the following functionality:
"Forget me" - Right to erasure
Mark profile as restricted - Right to restriction of processing
Export data - Right to portability
Allow profile editing - Right to rectification
See all my data - Right to access
Consent checkboxes
Age checks
Data destruction - Data minimization principle
This module complies to the GDPR law by not storing any identifiable information about a data subject. The only reference is the username which is not linked to any personal data.
In order to add personal data to your application you should create your own data schema and use the username column as a foreign key to your data. As a tip you should have a boolean flag to mark the personal data as restricted to comply to the right to restriction of processing which means that if you need to handle the data, e.g.: send a bulk email from a mailing list you are not allowed to do so if the flag is true.
The right to erasure does not mean that you must wipe all records from your application, e.g.: in a bank this right cannot be used to erase a running loan or debt. You are allowed to keep your application data but must erase the personal data. In case of Vert.x Auth JDBC you should delete your table but can still use a foreign key to the username as long as is not possible to link the username to the personal data.
Important note is that this must survive backups! As a tip backup the data, and data erasure on different archives so they can be replayed individually.
Like any application there will be a time where you need to store new users into the database. Has you have learn passwords are not stored in plain text but hashed according to the hashing strategy. The same strategy is required to hash new password before storing it to the database. Doing it is a 3 step task.
Generate a salt string
Hash the password given the salt string
Store it to the database
var salt = auth.generateSalt()
var hash = auth.computeHash("sausages", salt)
// save to the database
conn.updateWithParamsFuture("INSERT INTO user VALUES (?, ?, ?)", new io.vertx.core.json.JsonArray().add("tim").add(hash).add(salt)).onComplete{
case Success(result) => {
// success!
}
case Failure(cause) => println("Failure")
}
Warning
|
Hashing user password with salt can be not enough, this approach his good enough for avoiding rainbow tables attacks or precomputed table attacks but if the attacker gets the database it will be easier to setup a brute force attack. This kind of attack is slower but all required information is given: the hash and the salt. |
To make the hash attack more complex the default strategy allows you to provide an application level list of nonces to be used in the computation. This list should not be stored in the database since it add an extra variable to the computation that is unknown, making the brute force attack as potentially the only way to crack the hash. You might want to refresh the nonces now and then so you should add and never remove entries to the list, for example:
auth.setNonces(new io.vertx.core.json.JsonArray().add("random_hash_1").add("random_hash_1"))
In order to decode there is no change required to the code, however to generate a new user you must specify which nonce (by it’s index) you want to use. If you look at the previous example, the usage is quite similar:
Generate a salt string
Hash the password given the salt string and choosen nonce
Store it to the database
auth.setNonces(new io.vertx.core.json.JsonArray().add("random_hash_1").add("random_hash_1"))
var salt = auth.generateSalt()
// we will pick the second nonce
var hash = auth.computeHash("sausages", salt, 1)
// save to the database
conn.updateWithParamsFuture("INSERT INTO user VALUES (?, ?, ?)", new io.vertx.core.json.JsonArray().add("tim").add(hash).add(salt)).onComplete{
case Success(result) => {
// success!
}
case Failure(cause) => println("Failure")
}
如果要使用默认的认证实现,认证信息中用了 username
和 password
字段进行表述:
var authInfo = new io.vertx.core.json.JsonObject().put("username", "tim").put("password", "sausages")
authProvider.authenticateFuture(authInfo).onComplete{
case Success(result) => {
var user = result
}
case Failure(cause) => {
println(s"$cause")
}
}
尽管Vert.X Auth自身并不要求使用特定的许可模型(它本身只是使用了不透明的字符串),但默认的实现使用了比较熟悉的:用户/角色/许可模型,这样在应用里你可以使用一个或者多个角色,而一个角色也可以拥有一个或者多个许可。
如果要验证一个用户是否拥有特定的许可,则需要将许可信息传递到
isAuthorised
中:
user.isAuthorizedFuture("commit_code").onComplete{
case Success(result) => {
var hasPermission = result
}
case Failure(cause) => {
println(s"$cause")
}
}
如果要验证一个用户是否属于特定角色,则可以使用前缀法给角色带上前缀表示:
user.isAuthorizedFuture("role:manager").onComplete{
case Success(result) => {
var hasRole = result
}
case Failure(cause) => {
println(s"$cause")
}
}
Vert.X中的默认角色前缀使用了 role:
,这个值可通过 setRolePrefix
进行更改。
@author <a href="mailto:julien@julienviet.com">Julien Viet</a> @author <a href="http://tfox.org">Tim Fox</a>