Django-social-auth是一个很好的集成第三方认证的库,其支持的库种类非常多,包括常用的Facebook,twitter,google,msn,甚至还包括weibo。如果期望能够快速的集成这些账户的话,这个库是一个很好的开始。
因为众所周知的原因,在国内是没有办法访问facebook等服务的,很自然的我们希望可以通过代理的方式来让这个库工作正常。经过简单分析,这个库在底层的数据通讯方面,使用urllib2。入手点就在让urllib2支持代理了。在Python的原始库中,urllib2仅仅支持http代理,而我们使用SSH之类的用的是sock5。
经搜索发现已有网友提供了方案:
http://panweizeng.com/python-urllib2-socks-proxy.html
可是这个方法只解决了一半的问题,另一半就是DNS解析。于是又找到如下方案:
http://blog.antmanler.com/?p=471
需要说明的是,上边连接中的_create_connection与python2.7的不兼容,需要增加一个source_address=None的参数即可。
好了,至此让urllib2支持sock5的准备工作全部就绪,剩下的就是修改django-social-auth。查看其源代码,很快就能找到,这个库调用urlib2的地方被统一打包utils.py中到一个叫做dsa_open的函数。直接将上边两个链接中提到的方法,给这个函数打个补丁即可。
修改完成后的版本如下:
def dsa_urlopen(*args, **kwargs): """Like urllib2.urlopen but sets a timeout defined by SOCIAL_AUTH_URLOPEN_TIMEOUT setting if defined (and not already in kwargs).""" timeout = setting('SOCIAL_AUTH_URLOPEN_TIMEOUT') if timeout and 'timeout' not in kwargs: kwargs['timeout'] = timeout import socks import socket socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 1080) socket.socket = socks.socksocket def _create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,source_address=None): msg = "getaddrinfo returns an empty list" host, port = address for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res sock = None try: sock = socket.socket(af, socktype, proto) if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: sock.settimeout(timeout) sock.connect(address) return sock except socket.error, msg: if sock is not None: sock.close() raise socket.error, msg socket.create_connection = _create_connection return urlopen(*args, **kwargs)
对了,这个方案需要一个叫做socksipy_branch库的支持。可以使用pip安装。
此方法仍未完全解决DNS问题,最终方案需参照:http://www.cnblogs.com/Ankh/archive/2012/12/21/2827386.html