文档章节

使用URL认证简化资源连接

pseudo
 pseudo
发布于 2015/07/14 09:52
字数 1054
阅读 945
收藏 1

URL中的认证部分

URL(统一资源定位符)是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。它的结构如下:

scheme://[user:password@]domain:port/path?query_string#fragment_id

其中[user:password@]是可选部分,它定义了访问者的认证信息(userinfo)。比如我们使用ftp下载时会这样访问wget ftp://name:123456@192.168.0.88/auto_LNMP.sh,其中name是用户名,123456是密码。

实例中的应用

redis

虽然在ftp下载时用到了url认证部分,但在编程连接某些资源时却经常另外写代码进行认证。比如使用jedis连接需要密码认证的redis时要

Jedis  redis = new Jedis ("127.0.0.1",6379);//连接redis
redis.auth("redis");//验证密码

或者通过jedis连接池取得时

jedisPool = new JedisPool(uri);
Jedis jedis = jedisPool.getResource();
jedis.auth(passowrd);
return jedis;

但通过查看JedisPool的构造函数:

  public JedisPool(final String host) {
    URI uri = URI.create(host);
    if (JedisURIHelper.isValid(uri)) {
      String h = uri.getHost();
      int port = uri.getPort();
      String password = JedisURIHelper.getPassword(uri);
      int database = JedisURIHelper.getDBIndex(uri);
      this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(h, port,
          Protocol.DEFAULT_TIMEOUT, password, database, null), new GenericObjectPoolConfig());
    } else {
      this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host,
          Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE, null),
          new GenericObjectPoolConfig());
    }
  }

我们发现它会从连接url中解析认证密码,所以我们大可不必每次连接都进行auth,只要在资源url中添加认证信息就可以了,比如redis://:test!%40345678()@127.0.0.1:6379 (因为redis只需要密码进行认证,所以无用户名,密码是test!@345678,认证信息中如果有特殊字符需要进行url编码)。使用代码如下

public class JedisHelper {
    JedisPool jedisPool;

    public RedisHelper(String uri) {
        jedisPool = new JedisPool(uri);
    }

    public Jedis getResource() {
        return jedisPool.getResource();
    }

    public void returnResource(Jedis jedis) {
        jedisPool.returnResourceObject(jedis);
    }
}

jdbc数据库连接

在使用jdbc连接数据库时我们常常要写这些代码

String url="jdbc:mysql://192.168.1.25:3306/lbs?useUnicode=true&characterEncoding=UTF-8";
        String user="root", password="root";
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection(url,user,password);
        System.out.println(conn.getMetaData().getDatabaseProductName());

但我们不能通过jdbc:mysql://root:root@192.168.1.25:3306/lbs?useUnicode=true&characterEncoding=UTF-8进行连接,因为

 public static Connection getConnection(String url)
        throws SQLException {

        java.util.Properties info = new java.util.Properties();
        return (getConnection(url, info, Reflection.getCallerClass()));
    }

很遗憾getConnection方法并没有像jedis那样从url中解析用户信息,而且jdbc mysql-connector的Driver实现类com.mysql.jdbc.NonRegisteringDriver在取得连接(方法connect(String url, Properties info))时也没有解析uri中的认证信息。

解决方法

编写Driver实现类的包装类

public class JDBCDriverWrapper implements Driver {
    Driver driver;

    public JDBCDriverWrapper(String driverClz) throws Exception {
        //因为一些Driver实现通过static代码块调用DriverManager.registerDriver进行自动注册,所以加载Driver类时不能实例化
        Class driverClass = Class.forName(driverClz, false, this.getClass().getClassLoader());
        driver = (Driver) driverClass.newInstance();
        //自动注册驱动
        DriverManager.registerDriver(this);
    }

    @Override
    public Connection connect(String url, Properties info) throws SQLException {
        //不能通过java.net.URI进行解析,可能是个bug吧。
        String tmp = url.split("://", 2)[1];
        int atIndex = tmp.indexOf('@');
        //如果url中包含认证信息,将认证信息存入info
        if (atIndex > 0) {
            String rawUserInfo = tmp.substring(0, atIndex);
            String[] userInfo = rawUserInfo.split(":", 2);
            info.put("user", URLDecoder.decode(userInfo[0]));
            info.put("password", URLDecoder.decode(userInfo[1]));
            return driver.connect(url.replace(rawUserInfo.concat("@"), ""), info);
        }
        return driver.connect(url, info);
    }

    @Override
    public boolean acceptsURL(String url) throws SQLException {
        return driver.acceptsURL(url);
    }

    @Override
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
        return driver.getPropertyInfo(url, info);
    }

    @Override
    public int getMajorVersion() {
        return driver.getMajorVersion();
    }

    @Override
    public int getMinorVersion() {
        return driver.getMinorVersion();
    }

    @Override
    public boolean jdbcCompliant() {
        return driver.jdbcCompliant();
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return driver.getParentLogger();
    }
}

这个类包装了具体jdbc驱动的实现类,并在connect方法中实现了解析认证的功能。使用示例如下

public class WrapperTest {
    public static void main(String[] args) throws Exception {
        String url="jdbc:mysql://root:root@192.168.1.25:3306/lbs?useUnicode=true&characterEncoding=UTF-8";
        new JDBCDriverWrapper("com.mysql.jdbc.Driver");
        Connection conn= DriverManager.getConnection(url);
        DatabaseMetaData meta = conn.getMetaData();
        System.out.println(meta.getDatabaseProductName()+":"+meta.getDatabaseProductVersion());
    }
}

结束语

通过uri访问资源时尽量使用标准的uri机制进行访问,以简化程序;在开发中间件或需要为用户提供资源访问url时也尽量按照标准uri格式进行解析,这样不但方便用户使用,也方便以后进行功能上的扩展。

© 著作权归作者所有

共有 人打赏支持
pseudo

pseudo

粉丝 85
博文 37
码字总数 35469
作品 3
朝阳
程序员
私信 提问
IdentityServer4 实现 OpenID Connect 和 OAuth 2.0

关于 OAuth 2.0 的相关内容,点击查看:ASP.NET WebApi OWIN 实现 OAuth 2.0 OpenID 是一个去中心化的网上身份认证系统。对于支持 OpenID 的网站,用户不需要记住像用户名和密码这样的传统验...

林羽恒
2017/06/19
0
0
OAuth 2.0 教程(翻译)

OAuth 2.0 (原文:http://tutorials.jenkov.com/oauth2/index.html) demo: https://github.com/qihaiyan/ng-boot-oauth OAuth 2.0 教程 OAuth 2.0 是一个开放的标准协议,允许应用程序访问......

QiHaiYan
2016/09/04
202
0
HTTP协议介绍

一.http协议 http协议的版本: http/0.9:诞生于1991,仅用户传输html文档,不能包含图片 http/1.0:引入MIME,支持多媒体数据的处理,keep-alive(保存连接),有缓存功能 http/1.1:支持更多的请求方法...

向下
2014/03/23
0
0
一步一步构建自己的管理系统① 之 Spring Security OAuth + jwt

现在Spring boot 极大的简化了 Spring Framework 应用程序的配置,通过简单的依赖配置即可实现程序的基本安全。 首先我们先了解一下 oauth 2.0 OAuth 2.0 的规范可以参考 : RFC 6749 OAuth...

Fly_f
2018/04/15
0
0
Kubernetes 可扩展 Admission 进入 Beta 阶段

Kubernetes API Server 中有一个功能,能让用户(对工作负载)进行决策,这一功能在 1.9 中已经走入成熟期。 Admission 是 Kubernetes 中最强大的工具之一,可以通过限制创建对象的方式来增强...

店家小二
2018/12/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用Maven打包Docker镜像-Jenkins版

前提:Jenkins服务器上安装好Docker,创建Jenkins任务,配置好代码来源,和Build配置: pom.xml中添加docker-maven-plugin: <plugin> <groupId>com.spotify</groupId> <artifactI......

莫在全
20分钟前
0
0
rabbitmq

灰暗
今天
1
0
Flink

flink HA部署 flink搭建,采用分布式部署方式,分别为A,B,C三个节点。其中A为master;A,B,C为worker。 本文使用的用户是hadoop用户(自己新建) 先决条件 Java 1.8.x or higher scala 自己使用...

-九天-
今天
2
0
数据中台和传统数仓的区别

中台系统把业务层同性的算法能力,服务能力,业务能力高度集成,有效组织 ,动态规划。更好的帮助上层业务。 今天就让我们看看关于数据中台的问答吧。 1 Q : 什么是数据中台? A : 数据中台是...

hblt-j
今天
5
0
Java在什么时候会出现内存泄漏

在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对...

群星纪元
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部