Vert.x 关于权限授权和认证(基于JWT)

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();
	}
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值