本文旨在用Vert.x,shiro JdbcRealm开发一个对restfu api进行鉴权的demo
Vert.x:参看 http://vertx.io
shiro:参看 http://shiro.apache.org/
业务逻辑很简单,就是实现用户登录验证,然后对restful api进行鉴权。
数据库用mysql。
数据库名:myshiro
数据表:
-- ---------------------------- -- Table structure for t_permission -- ---------------------------- DROP TABLE IF EXISTS `t_permission`; CREATE TABLE `t_permission` ( `id` int(11) NOT NULL, `permission` varchar(255) NOT NULL, `role_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for t_role -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(11) NOT NULL, `role_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for t_user_role -- ---------------------------- DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `id` int(11) NOT NULL, `user_id` int(11) DEFAULT NULL, `role_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
后台代码:
package com.wof.realtime.apigateway; import java.util.HashSet; import java.util.Set; import org.apache.shiro.realm.jdbc.JdbcRealm; import org.apache.tomcat.jdbc.pool.DataSource; import io.vertx.core.AbstractVerticle; import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.AuthProvider; import io.vertx.ext.auth.User; import io.vertx.ext.auth.shiro.ShiroAuth; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.Session; import io.vertx.ext.web.handler.AuthHandler; import io.vertx.ext.web.handler.BodyHandler; import io.vertx.ext.web.handler.CookieHandler; import io.vertx.ext.web.handler.RedirectAuthHandler; import io.vertx.ext.web.handler.SessionHandler; import io.vertx.ext.web.handler.UserSessionHandler; import io.vertx.ext.web.sstore.LocalSessionStore; public class ApiGatewayVerticle2 extends AbstractVerticle { private AuthProvider authProvider; @Override public void start(Future<Void> startFuture) throws Exception { // 用户权限信息-JDBC形式 JdbcRealm jdbcRealm = getJdbcRealm(); authProvider = ShiroAuth.create(vertx, jdbcRealm); // 路由器 Router router = Router.router(vertx); // 为所有route创建session handler router.route().handler(BodyHandler.create()); router.route().handler(CookieHandler.create()); router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)).setSessionTimeout(1000 * 60 * 1)); router.route().handler(UserSessionHandler.create(authProvider)); // 当请求中没有user session时,自动跳转到 /login AuthHandler authHandler = RedirectAuthHandler.create(authProvider, "/login"); Set<String> authorities = new HashSet<String>(); authHandler.addAuthorities(authorities); // 为所有需要鉴权的路由安装authHandler router.route("/").handler(authHandler); router.route("/api/*").handler(authHandler); // restful api 鉴权 router.get("/api/liaota/liaota").handler(this::listLiaotaHandler); router.put("/api/liaota/liaota/:id").handler(this::updateLiaotaHandler); router.post("/api/liaota/liaota/").handler(this::addLiaotaHandler); router.delete("/api/liaota/liaota/:id").handler(this::deleteLiaotaHandler); // 登录跳转、登录验证、登出处理handler router.get("/login").handler(this::loginHandler); router.post("/login-auth").handler(this::loginAuthHandler); router.get("/logout").handler(context -> { context.clearUser(); context.response().setStatusCode(302).putHeader("Location", "/").end(); }); // 启动httpServer vertx.createHttpServer().requestHandler(router::accept).listen(8080, h-> { if(h.succeeded()) System.out.println("server start."); else h.cause().printStackTrace(); }); } /** * 通过JDBC获取用户、角色、权限 * * @return */ private JdbcRealm getJdbcRealm(){ // 数据库连接池 此处用硬编码方式(生产环境用配置文件方式) DataSource dataSource = new DataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/myshiro?useUnicode=true&characterEncoding=utf8"); dataSource.setUsername("demo"); dataSource.setPassword("123456"); // 配置数据库断开后自动连接 dataSource.setLogAbandoned(true); dataSource.setRemoveAbandoned(true); dataSource.setRemoveAbandonedTimeout(60); dataSource.setTestWhileIdle(true); dataSource.setValidationQuery("select id from user where name='demo'"); // 配置jdbcRealm JdbcRealm jdbcRealm = new JdbcRealm(); jdbcRealm.setDataSource(dataSource); jdbcRealm.setPermissionsLookupEnabled(true);//true:允许查找角色的权限。false:只查找用户和角色,不会查找角色的权限。 // jdbcRealm.setAuthenticationCachingEnabled(false);//禁止缓存用户查询结果。禁止后,每次都要从数据库查询。 // jdbcRealm.setAuthorizationCachingEnabled(false);//禁止缓存角色,权限查询结果。禁止后,每次都要从数据库查询。 jdbcRealm.setCachingEnabled(false);//禁止缓存 // 修改查询数据库SQL,根据自己的数据库表结构进行修改。 jdbcRealm.setAuthenticationQuery("select password from t_user where username = ?"); jdbcRealm.setUserRolesQuery("select t_r.role_name from t_user_role t_ur " + "inner join t_role t_r on t_ur.role_id=t_r.id " + "inner join t_user t_u on t_u.id = t_ur.user_id where t_u.username = ?"); jdbcRealm.setPermissionsQuery("select permission from t_permission t_p " + "inner join t_role t_r on t_r.id = t_p.role_id where t_r.role_name = ?"); return jdbcRealm; } private void loginAuthHandler(RoutingContext context) { HttpServerRequest req = context.request(); MultiMap params = req.formAttributes(); String username = params.get("username"); String password = params.get("password"); Session session = context.session(); JsonObject authInfo = new JsonObject().put("username", username).put("password", password); authProvider.authenticate(authInfo, res -> { JsonObject json = new JsonObject(); json.put("message", "loginFail"); if (res.succeeded()) { json.put("message", "loginSuccess"); User user = res.result(); context.setUser(user); if (session != null) { session.regenerateId(); // 更新session id } } req.response().headers().set("Content-Type", "text/html; charset=UTF-8"); req.response().end(json.encode()); }); } private void loginHandler(RoutingContext context) { HttpServerRequest req = context.request(); req.response().headers().set("Content-Type", "text/html; charset=UTF-8"); req.response().end("login"); } private void listLiaotaHandler(RoutingContext context) { context.user().isAuthorised("query", h -> { if(h.result()) doSomething(context); else { authFail(context); } }); } private void updateLiaotaHandler(RoutingContext context) { context.user().isAuthorised("update", h -> { if(h.result()) doSomething(context); else { authFail(context); } }); } private void addLiaotaHandler(RoutingContext context) { context.user().isAuthorised("add", h -> { if(h.result()) doSomething(context); else { authFail(context); } }); } private void deleteLiaotaHandler(RoutingContext context) { context.user().isAuthorised("delete", h -> { if(h.result()) doSomething(context); else { authFail(context); } }); } private void doSomething(RoutingContext context){ System.out.println("鉴权通过,进行业务逻辑处理。"); JsonObject json = new JsonObject(); json.put("success", true).put("message", "业务处理完成。"); context.request().response().headers().set("Content-Type", "text/html; charset=UTF-8"); context.request().response().end(json.toString()); } private void authFail(RoutingContext context){ JsonObject json = new JsonObject(); json.put("success", false).put("message", "无此权限。"); context.request().response().headers().set("Content-Type", "text/html; charset=UTF-8"); context.request().response().end(json.toString()); } }
pom.xml需要引入:
<dependencies> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-core</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-web</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-auth-shiro</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>8.5.11</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-juli</artifactId> <version>8.5.11</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.26</version> </dependency> </dependencies>
相关推荐
- **Fluent API**:Vert.x 的 API 设计倾向于采用 Fluent 风格,使得代码更加简洁易读。 - **事件驱动**:大部分 API 基于事件驱动模型,当事件发生时,Vert.x 会通过回调函数通知开发者。 在实际使用 Vert.x 时...
4. **异步编程模型**:vert.x 的API设计鼓励使用非阻塞式编程,所有的I/O操作都是异步的,这意味着在等待I/O操作完成时,程序可以继续执行其他任务,提高了并发处理能力。 5. **消息总线(Message Bus)**:vert.x ...
- vert.x 使用Java的NIO API来实现高效、非阻塞I/O,这减少了系统资源的消耗,并提高了高并发场景下的性能。 3. **非阻塞I/O(NIO)**: - NIO(New Input/Output)是Java标准库提供的一种I/O模型,它允许在一个...
Vert.x是事件驱动的,其处理请求的高性能也是基于其事件机制。Vert.x的事件机制中有几个非常重要的概念:Event Loop、Event Loop Vertical、Worker Vertical、Event Bus、Vert.x Module。 Event Loop:即事件循环,...
标题中的“基于Vert.x(java)开发的API网关”指的是使用Vert.x框架构建的应用程序,该应用程序主要功能是作为API网关。API网关是一种架构模式,它充当客户端(如Web应用、移动应用或IoT设备)与后端服务之间的单一...
本教程将探讨如何使用Vert.x和Spring Boot结合来开发一个真实的MQTT服务器。 首先,让我们了解一下Vert.x。Vert.x是一个用于构建反应式应用的Java平台,它提供了一种事件驱动、非阻塞I/O模型,使得开发者可以高效地...
4. **HTTP 服务器**: Vert.x 提供了构建HTTP服务器的能力,让你可以快速创建RESTful API 或Web应用。通过`HttpServer`类,你可以设置路由处理程序,响应HTTP请求。 5. **打包成JAR**: 项目可能被打包成可执行的JAR ...
博文链接提供了额外的学习资源,可能包含对Vert.x使用方法的详细讲解,例如设置项目、创建Verticle、事件处理等方面的教程或案例分析。 【标签】"源码 工具" “源码”标签提醒我们关注Vert.x的可定制性和可扩展性...
- **HTTP 端点:** 使用 Vert.x 可以轻松创建 RESTful API 和 HTTP 端点,从而实现服务间的通信。 **2.3 组合异步操作** - **异步操作组合:** 在构建微服务时,经常需要将多个异步操作串联起来。Vert.x 提供了 ...
1. **Vert.x的反应式编程**:Vert.x鼓励采用反应式编程风格,即应用程序对事件做出响应,而不是等待结果。这种模式减少了不必要的资源消耗,提高了系统的响应性。 2. **多语言支持**:Vert.x支持多种编程语言,允许...
### Vert.x配置项VertxOptions的使用 #### 概述 在使用Vert.x框架开发分布式应用时,为了更好地控制和优化应用性能,开发者通常需要通过`VertxOptions`类来定制化配置Vert.x实例。`VertxOptions`是用于创建`Vertx`...
2. **多语言支持**:虽然主要用Java编写,但Vert.x 提供了API接口,支持其他如JavaScript、Ruby、Groovy、Ceylon等多种语言,这使得开发人员可以选择他们最熟悉的语言进行开发。 3. **模块化系统**:Vert.x 允许...
《Vert.x应用开发实例教程》旨在为Vert.x的初学者和大中专院校学生提供易于入门,全面了解和掌握Vert.x框架技术和应用的教材和辅导资料,为使用Vert.x开发实时应用和企业级应用打下良好的基础。
此外,与Netty等底层库相比,Vert.x提供了一套更高级的API,使得开发者可以更加专注于业务逻辑而非底层细节。 总之,理解和掌握Vert.x的线程模型对于构建高性能、可伸缩的应用至关重要。通过合理配置和使用不同的...
Java API 版本的Vert.x Core 手册是关于Vert.x框架的重要参考资料,该框架是用Java编写的高度可扩展的事件驱动平台,适用于构建现代的、反应式的微服务和网络应用。 Vert.x Core是其核心组件,提供了低级别的API,...
vert.x是内存占用极小的快速开发框架,springboot模版项目
- **Web客户端API**:使用Vert.x提供的客户端API来与外部服务进行交互。 #### 十一、暴露Web API - **Web子路由器**:可以使用子路由器来组织API的不同部分。 - **处理程序**:定义不同的处理程序来处理各种HTTP...
Vert.X-generator是基于javafx8开发的图形界面Vert.x代码生成器,使用 Apache FreeMarker 作为代码文件的模板,用户可以一键将数据库中的表生成为任意风格的.java代码文件(比如经典的三层模型);该工具支持所有实现JDBC...
8. **语言无关性**:虽然vert.x是用Java实现的,但其API设计为与语言无关,可以与JavaScript、Ruby、Groovy、Ceylon等多种语言一起使用。 9. **Integration with other frameworks**:vert.x 可以轻松与其他Java...