`
domain2004
  • 浏览: 6342 次
  • 来自: ...
文章分类
社区版块
存档分类
最新评论

用Vert.x shiro jdbcRealm对restful api鉴权

阅读更多

本文旨在用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&amp;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>

 

 

 

分享到:
评论

相关推荐

    Vert.x 4 核心手册中文版

    - **Fluent API**:Vert.x 的 API 设计倾向于采用 Fluent 风格,使得代码更加简洁易读。 - **事件驱动**:大部分 API 基于事件驱动模型,当事件发生时,Vert.x 会通过回调函数通知开发者。 在实际使用 Vert.x 时...

    vert.x中文 PDF 下载

    4. **异步编程模型**:vert.x 的API设计鼓励使用非阻塞式编程,所有的I/O操作都是异步的,这意味着在等待I/O操作完成时,程序可以继续执行其他任务,提高了并发处理能力。 5. **消息总线(Message Bus)**:vert.x ...

    vert.x-2.1.2

    - vert.x 使用Java的NIO API来实现高效、非阻塞I/O,这减少了系统资源的消耗,并提高了高并发场景下的性能。 3. **非阻塞I/O(NIO)**: - NIO(New Input/Output)是Java标准库提供的一种I/O模型,它允许在一个...

    Vert.x应用开发实例教程

    Vert.x是事件驱动的,其处理请求的高性能也是基于其事件机制。Vert.x的事件机制中有几个非常重要的概念:Event Loop、Event Loop Vertical、Worker Vertical、Event Bus、Vert.x Module。 Event Loop:即事件循环,...

    基于Vert.x(java)开发的API网关,是一个分布式,全异步,高性能,可扩展,轻.zip

    标题中的“基于Vert.x(java)开发的API网关”指的是使用Vert.x框架构建的应用程序,该应用程序主要功能是作为API网关。API网关是一种架构模式,它充当客户端(如Web应用、移动应用或IoT设备)与后端服务之间的单一...

    vert.x结合springboot开发mqtt服务,真实可用

    本教程将探讨如何使用Vert.x和Spring Boot结合来开发一个真实的MQTT服务器。 首先,让我们了解一下Vert.x。Vert.x是一个用于构建反应式应用的Java平台,它提供了一种事件驱动、非阻塞I/O模型,使得开发者可以高效地...

    Vert.x 初始demo

    4. **HTTP 服务器**: Vert.x 提供了构建HTTP服务器的能力,让你可以快速创建RESTful API 或Web应用。通过`HttpServer`类,你可以设置路由处理程序,响应HTTP请求。 5. **打包成JAR**: 项目可能被打包成可执行的JAR ...

    Vert.x学习

    博文链接提供了额外的学习资源,可能包含对Vert.x使用方法的详细讲解,例如设置项目、创建Verticle、事件处理等方面的教程或案例分析。 【标签】"源码 工具" “源码”标签提醒我们关注Vert.x的可定制性和可扩展性...

    Java vert.x微服务框架资料

    - **HTTP 端点:** 使用 Vert.x 可以轻松创建 RESTful API 和 HTTP 端点,从而实现服务间的通信。 **2.3 组合异步操作** - **异步操作组合:** 在构建微服务时,经常需要将多个异步操作串联起来。Vert.x 提供了 ...

    vert.x 3.3.3

    1. **Vert.x的反应式编程**:Vert.x鼓励采用反应式编程风格,即应用程序对事件做出响应,而不是等待结果。这种模式减少了不必要的资源消耗,提高了系统的响应性。 2. **多语言支持**:Vert.x支持多种编程语言,允许...

    Vert.x配置项VertxOptions的使用

    ### Vert.x配置项VertxOptions的使用 #### 概述 在使用Vert.x框架开发分布式应用时,为了更好地控制和优化应用性能,开发者通常需要通过`VertxOptions`类来定制化配置Vert.x实例。`VertxOptions`是用于创建`Vertx`...

    使用Eclipse_Vert.x开发响应式应用_英文.pdf

    2. **多语言支持**:虽然主要用Java编写,但Vert.x 提供了API接口,支持其他如JavaScript、Ruby、Groovy、Ceylon等多种语言,这使得开发人员可以选择他们最熟悉的语言进行开发。 3. **模块化系统**:Vert.x 允许...

    vertx应用开发实例教程-完整版

     《Vert.x应用开发实例教程》旨在为Vert.x的初学者和大中专院校学生提供易于入门,全面了解和掌握Vert.x框架技术和应用的教材和辅导资料,为使用Vert.x开发实时应用和企业级应用打下良好的基础。

    Vert.x线程模型揭秘

    此外,与Netty等底层库相比,Vert.x提供了一套更高级的API,使得开发者可以更加专注于业务逻辑而非底层细节。 总之,理解和掌握Vert.x的线程模型对于构建高性能、可伸缩的应用至关重要。通过合理配置和使用不同的...

    Java API 版本的Vert.x Core 手册等三本书

    Java API 版本的Vert.x Core 手册是关于Vert.x框架的重要参考资料,该框架是用Java编写的高度可扩展的事件驱动平台,适用于构建现代的、反应式的微服务和网络应用。 Vert.x Core是其核心组件,提供了低级别的API,...

    vert.x-springboot模版项目

    vert.x是内存占用极小的快速开发框架,springboot模版项目

    Vert.x for Java 开发者

    - **Web客户端API**:使用Vert.x提供的客户端API来与外部服务进行交互。 #### 十一、暴露Web API - **Web子路由器**:可以使用子路由器来组织API的不同部分。 - **处理程序**:定义不同的处理程序来处理各种HTTP...

    Vert.X-generator是基于javafx8开发的图形界面Vert.x代码生成器

    Vert.X-generator是基于javafx8开发的图形界面Vert.x代码生成器,使用 Apache FreeMarker 作为代码文件的模板,用户可以一键将数据库中的表生成为任意风格的.java代码文件(比如经典的三层模型);该工具支持所有实现JDBC...

    vert.x-3.4.0.tar.gz

    8. **语言无关性**:虽然vert.x是用Java实现的,但其API设计为与语言无关,可以与JavaScript、Ruby、Groovy、Ceylon等多种语言一起使用。 9. **Integration with other frameworks**:vert.x 可以轻松与其他Java...

Global site tag (gtag.js) - Google Analytics