徒手构建auth2.0验证平台(以qq为例)

auth2.0的功用:首先说一下为何须要auth2.0,auth2.0是开放平台互联协议,能够这样理解,A是行业中的小生,两手空空;B是行业大佬,财大气粗,有一大批人(用户群);这个时候A须要借用B的用户群信息来构建本身的项目中的某项功能,可是出于资源的保护和各方面缘由,B不相信A,不会让A接入本身的信任体系里面,A是没法直接获取B那边用户群的用户名和密码的,同时A又想借用B拥有的用户群信息来完善本身项目中的某些功能,这个时候就须要auth2.0来作中介,经过一些业务流程来实现A在没有B的用户群的直接信息(帐户和密码),能够间接的获取到B那边的用户群的其余信息(除了用户名和密码,如用户昵称等等),至于信息的开发程度,那得看B了。说白了就是如何使得A在没有B的用户群的密码和帐号的状况下获取B的用户群的其余的信息,auth2.0就是解决这样的问题html

其实不少拥有大的资源信息的网站或者公司都有本身的开发平台的,用来开放本身的一些资源信息,经过好比说auth2.0等一些折中的手段来达到拥有大的资源信息的网站或者公司和开发者的双赢的局面,由于拥有大的资源信息的网站或者公司的能够根据开发者开发出来的应用的类型来定向的判断用户类型,这样以后,拥有大的资源信息的网站或者公司就能够根据用户是什么类型的,定向的推送广告,作大数据分析,与此同时,开发者也能达到开发出本身完整的应用的目的,真正的双赢。python

先简略的讲一下auth2.0是怎么工做的,这里有一片好文章,你们能够看一下,这里我也讲一下:linux

其实auth2.0工做有几种模式:简化模式,密码模式,客户端模式,受权码模式,其中受权码模式是使用最多的,这里我就分析一下受权码模式,qq开放互联平台就是使用这种模式,以下图:git

首先明确一下角色,user-gent:用户(或者能够说是用户浏览器); client:第三方网站或者应用; authorization server:认证服务器,它不是被第三方网站或者应用所拥有的,是放在原来的全部者(如腾讯)那里的;resource owner:资源(如腾讯的qq用户群,为腾讯所拥有)存放的地方,它是能够和authorization server互通的;总共有四个对象。web

流程是这样运转的:ubuntu

步骤A:先是user-agent访问client,client须要肯定user-agent是谁,可是client没有user-agent的用户和密码,没法验证验证用户,因此将user-agent经过A步骤将重定向(导向)到authorization-server那里(若是是client是经过qq来验证用户,这个时候用户就会发现本身的浏览器跳到qq登陆的界面),同时重定向过程当中也会附带一些信息,方便后面的操做,这个步骤最重要的信息就是redirect url和client identifier这两个参数浏览器

步骤B(user authentication):用户在登陆界面就会输入用户名和密码给authorization server,authorization server发现用户名和密码正确,发现确实有这个用户存在,就会要用户是否受权给client给访问他的我的信息服务器

步骤C:获得了用户的容许以后,authorization server就会根据步骤A获得redirect url将用户重定向到client那里,同时携带authorization code和一些其余的信息给client,这以前的步骤对用户来都是可见的,后面的步骤对用户不可见cookie

步骤D:这个时候用户就来到了client这界面了,这个时候client就会获取authorization code,若是有这个参数,表明用户已经受权了,client就携带authorization code和redirect url访问authentication server,向其索要访问用户信息的access tokenapp

步骤E:若是authorization code没有是有效的,authorization server就会将access token发给client,同时access token是有期限的

步骤F:cleint就会携带获得的access token去访问resource owner,因为resource owner和authorization server是互通的,因此resource owner能够验证access token是否有效或者过时,若是有效和没有过时,那么就会容许client访问以前那个用户的一些信息了。

其实上面都是看文档得来的

好了,讲了auth2.0(其实确定由auth1.0,有兴趣能够本身去了解)流程以后,下面就是实现了。

环境:tornado, linux(linux mint 类ubuntu),新浪云,qq互联验证平台

新浪云申请免费域名之用,由于qq互联验证平台要一个真正的域名,不像优酷开发平台直接上一个ip地址就能够了。

先讲一下新浪云怎么申请免费域名(又到了看文档的时候了),这样子吧,先来图:

看到了上面的建立应用的按钮了吗?那就是你能够申请域名的按钮了,新浪云原理是这样子的,就是你将你的小应用开发好,而后将你的应用调试成其要求的环境,经过git或者svn这类的版本控制器将你的应用传到其要求的地方,而后你就能够经过其给你自定义的域名(域名是你建立的应用的时候,你本身指定的,我这里指定的是zhougch501.sinaapp.com)来访问你的应用了,其间的部署的工做,sina云已经帮你作好了,你不用担忧,方便不?

这之间有几个要注意地方:1.如何经过git或者svn来将本身的应用传上去,能够看这里,我我的推荐使用git,若是不会使用git,能够看这里,好了,我就建立一个应用作示范吧

固然先是点击建立应用按钮,这里我建立的应用是zhougch502

点击建立以后:

选择开发语言python2.7

而后就是建立罗,建立成功了以后就要进入应用的管理界面了,进入应用管理界面以后就能够点击代码管理了,而后他就会让你选择是git仍是svn,这里我选择的是git了

选择了git了以后就会在页面中显示如何将将代码上传到新浪云了,页面最下面的蓝色的连接有更细的说怎么作,你能够去看一下。

 

            2.如何将本身的应用调试新浪云要求的环境,这里面有详细的介绍(又到了看文档的时候了)

 

ok,到了讲解如何使用新浪云给的域名来在qq互联平台使用qq来实现auth2.0的认证流程,这里有了上面我讲解auth2.0的知识准备,这里就简单多了

先是看qq互联平台给的auth2.0文档,为何还要看文档^~^,由于qq互联平台对auth2.0标准认证流程作了一些改动,同时qq互联平台提供了两种接入方式,有网站接入和app接入,这里我讲解的是网站的接入。好了,在这个以前,我还要作一些准备工做。看这里 ,其实就是在qq互联平台上里面建立一个应用,和在新浪云里面同样,有木有,哈哈哈。流程截图以下:

 

看到了申请地址了没有,进入了以后就能够点击管理中心了,而后点击建立应用,而后选择应用类型为网站:

 

而后就是应用的信息填写,里面的信息怎么填写,填写界面都给出相应的信息和文档(又要看文档,醉了),里面网站地址就是以前在新浪云上面免费申请的网址,看到了吧,以前的工做是有用的

好了,这以后就有了qq互联平台的appid和appkey,不知道appid和appkey的孩子们,看这里,在未审核项里面就有你的刚刚建立的应用

 

点击你的应用进去以后就能够看到你的appid和appkey了

 

ok,准备工做已经完成了,而后你就能够根据我以前讲的auth2.0知识来参考qq互联给的文档来实现使用qq登陆让用户受权来获取用户信息。qq互联平台上也有代码示例,是使用PHP来实现的,会写程序的人都能看得懂的。

而后就是最后个人实现,你们能够点击这里试一下。

下面我在linux使用tornado(python)实现代码,能够参考一下,注意:这里代码是部署到新浪云的代码了

# -*- coding: utf-8 -*-

import tornado.wsgi
import os.path
import httplib
import urllib
import urllib2
import sae


from urllib import quote
class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        return self.get_secure_cookie("username")

class LoginHandler(BaseHandler):
    def get(self):
        self.render('login.html')

class WelcomeHandler(BaseHandler):
    # get code 
    def get(self):
        if self.get_argument("code", None) and str(self.get_argument("state", None)) == "test":
            # get token
            code = self.get_argument("code")
            redirect_url = quote("http://zhougch501.sinaapp.com/")
            req_url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=101265051&client_secret=b238da816c4e4dcb598836084dcea067&redirect_uri=" + redirect_url + "&code=" + code
            req = urllib2.Request(req_url)
            res_data = urllib2.urlopen(req)
            res = res_data.read()
            res = res.split("&")
            access_token = res[0].split("=")
            access_token = access_token[1]

            # 获取用户的openid
            req_url = "https://graph.qq.com/oauth2.0/me?access_token=" + access_token 
            req = urllib2.Request(req_url)
            res_data = urllib2.urlopen(req)
            res = res_data.read()

            # get openid
            # callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )
            res = res.split(",")
            res = res[1].split(":")
            res = res[1].split("\"")
            openid = res[1]


            # 获取用户的信息
            req_url = "https://graph.qq.com/user/get_user_info?access_token=" + access_token + "&oauth_consumer_key=101265051&openid=" + openid
            req = urllib2.Request(req_url)
            res_data = urllib2.urlopen(req)
            res = res_data.read()
            res.replace("{", "")
            res.replace("\"", "")
            res = res.split(",")
            name = ""
            # info = {}
            for index in range(len(res)):
                if index == 3:
                    name = (res[index].split(":"))[1]
            self.render("index.html", info=name)

        else:
               if self.current_user:
                   self.render('index.html', user=self.current_user)
               else:
                   self.redirect("/login")

class LoginQQHandler(BaseHandler):
    def get(self):
        redirect_url = quote("http://zhougch501.sinaapp.com/")
        req_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101265051&redirect_uri=" + redirect_url + "&state=test"
        self.redirect(req_url)

class LogoutHandler(BaseHandler):
    def get(self):
    # if (self.get_argument("logout", None)):
        self.clear_cookie("username")
        self.redirect("/")

        

settings = {
        "template_path": os.path.join(os.path.dirname(__file__), "templates"),
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
        "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=",
        "xsrf_cookies": True,
        "login_url": "/login"
    }

app = tornado.wsgi.WSGIApplication([
        (r'/', WelcomeHandler),
        (r'/login', LoginHandler),
        (r'/loginWithQQ', LoginQQHandler),
        (r'/logout', LogoutHandler)
    ], **settings)

application = sae.create_wsgi_app(app)
相关文章
相关标签/搜索