用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&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>
相关推荐
杜鲁门 2020-11-05
luckyxl0 2020-08-16
Dullonjiang 2020-08-09
xclxcl 2020-08-03
zmzmmf 2020-08-03
MicroBoy 2020-08-02
ganjing 2020-08-02
likesyour 2020-08-01
zmzmmf 2020-07-09
MicroBoy 2020-07-05
zzhao 2020-06-26
子云 2020-06-18
visionzheng 2020-06-07
neweastsun 2020-06-04
ErixHao 2020-06-03
GDreams0 2020-06-01
ganjing 2020-05-29
zmzmmf 2020-05-28
nullcy 2020-05-26