• 用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

    数据表:

     1 -- ----------------------------
     2 -- Table structure for t_permission
     3 -- ----------------------------
     4 DROP TABLE IF EXISTS `t_permission`;
     5 CREATE TABLE `t_permission` (
     6   `id` int(11) NOT NULL,
     7   `permission` varchar(255) NOT NULL,
     8   `role_id` int(11) DEFAULT NULL,
     9   PRIMARY KEY (`id`)
    10 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    11  
    12 -- ----------------------------
    13 -- Table structure for t_role
    14 -- ----------------------------
    15 DROP TABLE IF EXISTS `t_role`;
    16 CREATE TABLE `t_role` (
    17   `id` int(11) NOT NULL,
    18   `role_name` varchar(255) DEFAULT NULL,
    19   PRIMARY KEY (`id`)
    20 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    21  
    22 -- ----------------------------
    23 -- Table structure for t_user
    24 -- ----------------------------
    25 DROP TABLE IF EXISTS `t_user`;
    26 CREATE TABLE `t_user` (
    27   `id` int(11) NOT NULL,
    28   `username` varchar(255) DEFAULT NULL,
    29   `password` varchar(255) DEFAULT NULL,
    30   PRIMARY KEY (`id`)
    31 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    32  
    33 -- ----------------------------
    34 -- Table structure for t_user_role
    35 -- ----------------------------
    36 DROP TABLE IF EXISTS `t_user_role`;
    37 CREATE TABLE `t_user_role` (
    38   `id` int(11) NOT NULL,
    39   `user_id` int(11) DEFAULT NULL,
    40   `role_id` int(11) DEFAULT NULL,
    41   PRIMARY KEY (`id`)
    42 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    43  后台代码:
    44 
    45  
      1 package cn.endv.realtime.apigateway;
      2  
      3 import java.util.HashSet;
      4 import java.util.Set;
      5  
      6 import org.apache.shiro.realm.jdbc.JdbcRealm;
      7 import org.apache.tomcat.jdbc.pool.DataSource;
      8  
      9 import io.vertx.core.AbstractVerticle;
     10 import io.vertx.core.Future;
     11 import io.vertx.core.MultiMap;
     12 import io.vertx.core.http.HttpServer;
     13 import io.vertx.core.http.HttpServerRequest;
     14 import io.vertx.core.json.JsonObject;
     15 import io.vertx.ext.auth.AuthProvider;
     16 import io.vertx.ext.auth.User;
     17 import io.vertx.ext.auth.shiro.ShiroAuth;
     18 import io.vertx.ext.web.Router;
     19 import io.vertx.ext.web.RoutingContext;
     20 import io.vertx.ext.web.Session;
     21 import io.vertx.ext.web.handler.AuthHandler;
     22 import io.vertx.ext.web.handler.BodyHandler;
     23 import io.vertx.ext.web.handler.CookieHandler;
     24 import io.vertx.ext.web.handler.RedirectAuthHandler;
     25 import io.vertx.ext.web.handler.SessionHandler;
     26 import io.vertx.ext.web.handler.UserSessionHandler;
     27 import io.vertx.ext.web.sstore.LocalSessionStore;
     28  
     29 public class ApiGatewayVerticle2 extends AbstractVerticle {
     30     
     31     private AuthProvider authProvider;
     32     
     33     @Override
     34     public void start(Future<Void> startFuture) throws Exception {
     35         
     36         // 用户权限信息-JDBC形式        
     37         JdbcRealm jdbcRealm = getJdbcRealm();
     38         authProvider = ShiroAuth.create(vertx, jdbcRealm);
     39         
     40         // 路由器
     41         Router router = Router.router(vertx);
     42         
     43         // 为所有route创建session handler
     44         router.route().handler(BodyHandler.create());
     45         router.route().handler(CookieHandler.create());
     46         router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)).setSessionTimeout(1000 * 60 * 1));            
     47         router.route().handler(UserSessionHandler.create(authProvider));
     48         
     49         // 当请求中没有user session时,自动跳转到 /login
     50         AuthHandler authHandler = RedirectAuthHandler.create(authProvider, "/login"); 
     51         Set<String> authorities = new HashSet<String>();
     52         authHandler.addAuthorities(authorities);
     53  
     54         // 为所有需要鉴权的路由安装authHandler
     55         router.route("/").handler(authHandler);
     56         router.route("/api/*").handler(authHandler);
     57         
     58         // restful api 鉴权
     59         router.get("/api/liaota/liaota").handler(this::listLiaotaHandler);
     60         router.put("/api/liaota/liaota/:id").handler(this::updateLiaotaHandler);
     61         router.post("/api/liaota/liaota/").handler(this::addLiaotaHandler);
     62         router.delete("/api/liaota/liaota/:id").handler(this::deleteLiaotaHandler);
     63                     
     64         // 登录跳转、登录验证、登出处理handler
     65         router.get("/login").handler(this::loginHandler);
     66         router.post("/login-auth").handler(this::loginAuthHandler);
     67         router.get("/logout").handler(context -> {
     68             context.clearUser();
     69             context.response().setStatusCode(302).putHeader("Location", "/").end();
     70         });                    
     71         
     72         // 启动httpServer
     73         vertx.createHttpServer().requestHandler(router::accept).listen(8080, h-> {
     74             if(h.succeeded())
     75                 System.out.println("server start.");
     76             else 
     77                 h.cause().printStackTrace();
     78         });
     79     }
     80     
     81     /**
     82      * 通过JDBC获取用户、角色、权限
     83      * 
     84      * @return
     85      */
     86     private JdbcRealm getJdbcRealm(){
     87         // 数据库连接池 此处用硬编码方式(生产环境用配置文件方式)
     88         DataSource dataSource = new DataSource();
     89         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
     90         dataSource.setUrl("jdbc:mysql://localhost:3306/myshiro?useUnicode=true&amp;characterEncoding=utf8");
     91         dataSource.setUsername("demo");
     92         dataSource.setPassword("123456");
     93         // 配置数据库断开后自动连接
     94         dataSource.setLogAbandoned(true);
     95         dataSource.setRemoveAbandoned(true);
     96         dataSource.setRemoveAbandonedTimeout(60);
     97         dataSource.setTestWhileIdle(true);
     98         dataSource.setValidationQuery("select id from user where name='demo'");
     99         
    100         // 配置jdbcRealm
    101         JdbcRealm jdbcRealm = new JdbcRealm();
    102         jdbcRealm.setDataSource(dataSource);
    103         jdbcRealm.setPermissionsLookupEnabled(true);//true:允许查找角色的权限。false:只查找用户和角色,不会查找角色的权限。
    104         
    105 //        jdbcRealm.setAuthenticationCachingEnabled(false);//禁止缓存用户查询结果。禁止后,每次都要从数据库查询。
    106 //        jdbcRealm.setAuthorizationCachingEnabled(false);//禁止缓存角色,权限查询结果。禁止后,每次都要从数据库查询。
    107         jdbcRealm.setCachingEnabled(false);//禁止缓存
    108         
    109         // 修改查询数据库SQL,根据自己的数据库表结构进行修改。
    110         jdbcRealm.setAuthenticationQuery("select password from t_user where username = ?");
    111         jdbcRealm.setUserRolesQuery("select t_r.role_name from t_user_role t_ur "
    112                 + "inner join t_role t_r on t_ur.role_id=t_r.id  "
    113                 + "inner join t_user t_u on t_u.id = t_ur.user_id where t_u.username = ?");
    114         jdbcRealm.setPermissionsQuery("select permission from t_permission t_p "
    115                 + "inner join t_role t_r on t_r.id = t_p.role_id where t_r.role_name = ?");    
    116         
    117         return jdbcRealm;
    118     }
    119     
    120     private void loginAuthHandler(RoutingContext context) {
    121         HttpServerRequest req = context.request();
    122         MultiMap params = req.formAttributes();
    123         String username = params.get("username");
    124         String password = params.get("password");
    125  
    126         Session session = context.session();
    127         JsonObject authInfo = new JsonObject().put("username", username).put("password", password);
    128         
    129         authProvider.authenticate(authInfo, res -> {
    130             JsonObject json = new JsonObject();
    131             json.put("message", "loginFail");
    132     
    133             if (res.succeeded()) {
    134                 json.put("message", "loginSuccess");
    135                 User user = res.result();
    136                 context.setUser(user);
    137                 if (session != null) {
    138                     session.regenerateId(); // 更新session id    
    139                 }
    140             }
    141             req.response().headers().set("Content-Type", "text/html; charset=UTF-8");
    142             req.response().end(json.encode());
    143         });
    144     }
    145     
    146     private void loginHandler(RoutingContext context) {
    147         HttpServerRequest req = context.request();
    148         req.response().headers().set("Content-Type", "text/html; charset=UTF-8");
    149         req.response().end("login");
    150     }
    151     
    152     private void listLiaotaHandler(RoutingContext context) {
    153         context.user().isAuthorised("query", h -> {
    154             if(h.result())
    155                 doSomething(context);
    156             else {
    157                 authFail(context);
    158             }
    159         });
    160     }
    161     
    162     private void updateLiaotaHandler(RoutingContext context) {
    163         context.user().isAuthorised("update", h -> {
    164             if(h.result())
    165                 doSomething(context);
    166             else {
    167                 authFail(context);
    168             }
    169         });
    170     }
    171     
    172     private void addLiaotaHandler(RoutingContext context) {
    173         context.user().isAuthorised("add", h -> {
    174             if(h.result())
    175                 doSomething(context);
    176             else {
    177                 authFail(context);
    178             }
    179         });
    180     }
    181     
    182     private void deleteLiaotaHandler(RoutingContext context) {
    183         context.user().isAuthorised("delete", h -> {
    184             if(h.result())
    185                 doSomething(context);
    186             else {
    187                 authFail(context);
    188             }
    189         });
    190     }
    191     
    192     private void doSomething(RoutingContext context){
    193         System.out.println("鉴权通过,进行业务逻辑处理。");
    194         JsonObject json = new JsonObject();
    195         json.put("success", true).put("message", "业务处理完成。");
    196         context.request().response().headers().set("Content-Type", "text/html; charset=UTF-8");
    197         context.request().response().end(json.toString());
    198     }
    199     
    200     private void authFail(RoutingContext context){
    201         JsonObject json = new JsonObject();
    202         json.put("success", false).put("message", "无此权限。");
    203         context.request().response().headers().set("Content-Type", "text/html; charset=UTF-8");
    204         context.request().response().end(json.toString());
    205     }
    206  
    207 }

    pom.xml需要引入:

     1     <dependencies>
     2         <dependency>
     3             <groupId>io.vertx</groupId>
     4             <artifactId>vertx-core</artifactId>
     5             <version>3.4.2</version>
     6         </dependency>
     7         <dependency>
     8             <groupId>io.vertx</groupId>
     9             <artifactId>vertx-web</artifactId>
    10             <version>3.4.2</version>
    11         </dependency>
    12         <dependency>
    13             <groupId>io.vertx</groupId>
    14             <artifactId>vertx-auth-shiro</artifactId>
    15             <version>3.4.2</version>
    16         </dependency>
    17         <dependency>
    18             <groupId>org.apache.tomcat</groupId>
    19             <artifactId>tomcat-jdbc</artifactId>
    20             <version>8.5.11</version>
    21         </dependency>
    22         <dependency>
    23             <groupId>org.apache.tomcat</groupId>
    24             <artifactId>tomcat-juli</artifactId>
    25             <version>8.5.11</version>
    26         </dependency>
    27         <dependency>
    28             <groupId>mysql</groupId>
    29             <artifactId>mysql-connector-java</artifactId>
    30             <version>5.1.26</version>
    31         </dependency>
    32     </dependencies>
  • 相关阅读:
    ActiveReport9 在MVC4项目中出错
    EntityFramework5.0 DataBase-First 在三层架构中的使用,分离实体类到Model层。
    SqlServer存在并删除 表,函数,view等
    Visual Studio常用技巧与插件
    让 WPF 应用程序单例化
    C# 常用加密方法一 AES 与 DES
    Windows 的公共文件夹
    Hibernate中Criteria的完整用法
    maven依赖关系中Scope的作用
    Eclipse取消设置项目默认空间
  • 原文地址:https://www.cnblogs.com/endv/p/14226661.html
Copyright © 2020-2023  润新知