vertx也用了有一段时间,起初对其使用都基于固有的模块在用,官网的教程也比较详细,虽然使用过程中有些问题还需要自己研究尝试,整体来说还算顺利,但是最近在使用其授权、认证的模块,官方的文档还是保持着原有的言简意赅,有些东西看了实例代码还是一头雾水,尤其是权限认证的方式,特将研究的内容发出来,一来可以共享信息,方便大家斧正,二来也做为记录
package zzy.verticles; import io.vertx.core.*; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.JWTOptions; import io.vertx.ext.auth.KeyStoreOptions; import io.vertx.ext.auth.PubSecKeyOptions; import io.vertx.ext.auth.User; import io.vertx.ext.auth.authorization.Authorization; import io.vertx.ext.auth.authorization.AuthorizationProvider; import io.vertx.ext.auth.authorization.PermissionBasedAuthorization; import io.vertx.ext.auth.authorization.RoleBasedAuthorization; import io.vertx.ext.auth.jwt.JWTAuth; import io.vertx.ext.auth.jwt.JWTAuthOptions; import io.vertx.ext.auth.jwt.authorization.JWTAuthorization; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.AuthorizationHandler; import io.vertx.ext.web.handler.JWTAuthHandler; import io.vertx.mysqlclient.MySQLConnectOptions; import io.vertx.mysqlclient.MySQLPool; import io.vertx.sqlclient.PoolOptions; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; import java.util.HashSet; import java.util.Set; public class WebJWTAuthVerticle extends AbstractVerticle { @Override public void start(Promise<Void> startPromise) throws Exception { try { // MySQL MySQLConnectOptions mySQLConnectOptions = new MySQLConnectOptions() .setPort(3306) .setHost("localhost") .setDatabase("sqlauth") .setUser("root") .setPassword("qwe!23"); PoolOptions poolOptions = new PoolOptions() .setMaxSize(5); MySQLPool client = MySQLPool.pool(vertx, mySQLConnectOptions, poolOptions); / Router router = Router.router(vertx); // Create a JWT Auth Provider // JWTAuth jwt = JWTAuth.create(vertx, new JWTAuthOptions() // .setKeyStore(new KeyStoreOptions() // .setType("jceks") // .setPath("keystore.jceks") // .setPassword("secret"))); // 采用RSA256的加密文件方式来进行验证 // 读取private key Buffer privateBuffer = vertx.fileSystem().readFileBlocking("RSA/private_key.pem"); // 读取public key Buffer publicBuffer = vertx.fileSystem().readFileBlocking("RSA/public.pem"); // create a jwt auth provider with rsa JWTAuth jwt = JWTAuth.create(vertx, new JWTAuthOptions() .addPubSecKey(new PubSecKeyOptions() .setAlgorithm("RS256") .setBuffer(publicBuffer) ) .addPubSecKey(new PubSecKeyOptions() .setAlgorithm("RS256") .setBuffer(privateBuffer) ) ); // 从数据库中验证用户是否合法存在,如果存在就将permission都加到token中 router.get("/api/newToken").handler(ctx -> { // 获取用户名,密码 String username = ctx.request().getParam("username"); String password = ctx.request().getParam("password"); if (username != null && password != null) { // 验证用户名 密码是否合法 String salt = "adminf7a0d5382ed7470b8ecee156b3deecd0"; String salt_password = "73421c3118a2be82fdd06cbb66041bdb"; String computed_password = md5_salt(password, salt); if (computed_password.equals(salt_password)) { // 开始查询数据库返回对应用户的权限列表 client .query("select perm from roles_perms\n" + "where role = \"admin\"") .execute(ar -> { if (ar.succeeded()) { RowSet<Row> result = ar.result(); JsonArray perms = new JsonArray(); JsonArray roles = new JsonArray(); result.forEach(row -> { if (row.getValue("perm").toString().contains("role:")) { roles.add(row.getValue("perm")); } else { perms.add(row.getValue("perm")); } }); // 返回token ctx.response().putHeader("Content-Type", "text/plain"); // String token = jwt.generateToken(new JsonObject().put("permissions", perms), // new JWTOptions().setIgnoreExpiration(false).setExpiresInMinutes(30).setAlgorithm("RS256")); String token = jwt.generateToken(new JsonObject().put("permissions", perms).put("role", roles), new JWTOptions().setIgnoreExpiration(false).setExpiresInMinutes(30).setAlgorithm("RS256")); ctx.response().end( token ); } else { System.out.println(ar.cause().getMessage()); ctx.response().setStatusCode(401).end(); } }); } else { ctx.response().setStatusCode(401).end(); } } else { ctx.response().setStatusCode(401).end(); } }); // 配置授权 JWTAuthHandler authHandler = JWTAuthHandler.create(jwt); AuthorizationProvider authzProvider = JWTAuthorization.create("permissions"); // permissions // 配置所有的保护接口 router.route("/api/*").handler(authHandler); // 不需要校验permission的内容 router.get("/api/protected").handler(ctx -> { ctx.response().putHeader("Content-Type", "text/plain"); ctx.response().end("this secret is not defcon!"); }); // 通过permission来判定接口是否访问 router.route("/api/protected/defcon1") .handler( AuthorizationHandler.create( PermissionBasedAuthorization.create("defcon1") ) .addAuthorizationProvider(authzProvider)) .handler(ctx -> { ctx.response().putHeader("Content-Type", "text/plain"); ctx.response().end("this secret is defcon1!"); }); // 通过new 接口实现了一个匿名类,用来处理权限的列表认证 AuthorizationProvider authorizationProvider = new AuthorizationProvider() { @Override public String getId() { return "role"; } @Override public void getAuthorizations(User user, Handler<AsyncResult<Void>> handler) { JsonArray roles = user.attributes().getJsonObject("accessToken").getJsonArray(getId()); final Set<Authorization> authorizations = new HashSet<>(); if (roles != null && roles.size() >= 0) { for (Object el : roles) { // convert to the authorization type if (el instanceof String) { authorizations.add(RoleBasedAuthorization.create((String) el)); } else { // abort the parsing handler.handle(Future.failedFuture("Cannot parse role: " + el)); return; } } } user.authorizations().add(getId(), authorizations); // return handler.handle(Future.succeededFuture()); } }; // 对于权限列表认证的处理方法 router.route("/api/protected/role") .handler( AuthorizationHandler.create( RoleBasedAuthorization.create("role:admin") ) .addAuthorizationProvider(authorizationProvider) ).handler(ctx -> { ctx.response().putHeader("Content-Type", "text/plain"); ctx.response().end("this secret is defcon1!"); }); vertx.createHttpServer().requestHandler(router).listen(8989); startPromise.complete(); } catch (Exception ex) { ex.printStackTrace(); } } private String md5_salt(String password, String salt) { //加密方式 String hashAlgorithmName = "MD5"; //盐:相同密码使用不同的盐加密后的结果不同 ByteSource byteSalt = ByteSource.Util.bytes(salt); //密码 Object source = password; //加密次数 int hashIterations = 2; SimpleHash result = new SimpleHash(hashAlgorithmName, source, byteSalt, hashIterations); return result.toString(); } }
Vert.x 关于权限授权和认证(基于JWT)
最新推荐文章于 2022-11-22 11:38:02 发布