QQ、Sina等OAuth2.0接入
来源:互联网 发布:濒死体验知乎 编辑:程序博客网 时间:2024/06/07 01:26
OAuth2.0技术比较实用,像我这种反感注册的用户一般都是申请一个没用的QQ,然后用这个QQ登录那些不想注册,有点小用的系统。技术不多说,拿QQ来说,简单列几点:
1.QQ给第三方平台分配一个appkey和appsecret
2.用户选择使用QQ账号登录第三方平台,此时,第三方平台使用自己的appkey获取code,code是在用户输入QQ账号密码后生成的,是与QQ那边交互的,并且生命周期很短,是安全的
3.第三方平台获取到code后,再使用code+appkey+appsecret获取access_token
4.第三方平台获取到access_token后,便可使用该access_token获取openid,进而使用openid+access_token+appkey获取用户信息
5.此时用户已认证成功,第三方平台可使用该用户的唯一标示openid来创建账号
tornado框架封装的OAuth2Mixin:
class OAuth2Mixin(object): """Abstract implementation of OAuth 2.0. See `FacebookGraphMixin` below for an example implementation. Class attributes: * ``_OAUTH_AUTHORIZE_URL``: The service's authorization url. * ``_OAUTH_ACCESS_TOKEN_URL``: The service's access token url. """ @return_future def authorize_redirect(self, redirect_uri=None, client_id=None, client_secret=None, extra_params=None, callback=None): """Redirects the user to obtain OAuth authorization for this service. Some providers require that you register a redirect URL with your application instead of passing one via this method. You should call this method to log the user in, and then call ``get_authenticated_user`` in the handler for your redirect URL to complete the authorization process. .. versionchanged:: 3.1 Returns a `.Future` and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with `OAuthMixin.authorize_redirect`. """ args = { "redirect_uri": redirect_uri, "client_id": client_id } if extra_params: args.update(extra_params) self.redirect( url_concat(self._OAUTH_AUTHORIZE_URL, args)) callback() def _oauth_request_token_url(self, redirect_uri=None, client_id=None, client_secret=None, code=None, extra_params=None): url = self._OAUTH_ACCESS_TOKEN_URL args = dict( redirect_uri=redirect_uri, code=code, client_id=client_id, client_secret=client_secret, ) if extra_params: args.update(extra_params) return url_concat(url, args)
QQ Oauth2.0封装:
class QQGraphOAuth2Mixin(OAuth2Mixin): _OAUTH_AUTHORIZE_URL = "https://graph.qq.com/oauth2.0/authorize?" _OAUTH_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token?" _OAUTH_OPENID_URL = "https://graph.qq.com/oauth2.0/me?" _OAUTH_NO_CALLBACKS = False _QQ_BASE_URL = "https://graph.qq.com" @_auth_return_future def get_authenticated_user(self, redirect_uri, client_id, client_secret, code, callback, extra_fields=None, extra_params=None): http = self.get_auth_http_client() args = { "redirect_uri": redirect_uri, "code": code, "client_id": client_id, "client_secret": client_secret, "extra_params": extra_params, } http.fetch(self._oauth_request_token_url(**args), self.async_callback(self._on_access_token, redirect_uri, client_id, client_secret, callback, extra_fields)) def _on_access_token(self, redirect_uri, client_id, client_secret, future, extra_fields, response): if response.error: future.set_exception(AuthError('QQ auth error: %s' % str(response))) return args = escape.parse_qs_bytes(escape.native_str(response.body)) session = { "access_token": args["access_token"][-1], "expires_in": args["expires_in"][-1], "refresh_token": args["refresh_token"][-1], "client_id": client_id, } http = self.get_auth_http_client() http.fetch(self._oauth_request_openid(session["access_token"]), self.async_callback(self._on_open_id, future, session, extra_fields)) def _on_open_id(self, future, session, extra_fields, response): if response.error: future.set_exception(AuthError('QQ auth error: %s' % str(response))) return response = response.body.replace("callback( ", "").replace(" );", "") args = escape.json_decode(response) session["openid"] = str(args["openid"]) fields = set(['ret', 'msg', 'nickname']) if extra_fields: fields.update(extra_fields) self.qq_request( path="/user/get_user_info", callback=self.async_callback( self._on_get_user_info, future, session, fields), access_token=session["access_token"], openid=session["openid"], oauth_consumer_key=session["client_id"], fields=",".join(fields) ) def _on_get_user_info(self, future, session, fields, user): if user is None: future.set_result(None) return fieldmap = {} for field in fields: fieldmap[field] = user.get(field) fieldmap.update(session) future.set_result(fieldmap) @_auth_return_future def qq_request(self, path, callback, access_token=None, post_args=None, **args): url = self._QQ_BASE_URL + path all_args = {} if access_token: all_args["access_token"] = access_token all_args.update(args) if all_args: url += "?" + urllib_parse.urlencode(all_args) callback = self.async_callback(self._on_qq_request, callback) http = self.get_auth_http_client() if post_args is not None: http.fetch(url, method="POST", body=urllib_parse.urlencode(post_args), callback=callback) else: http.fetch(url, callback=callback) def _on_qq_request(self, future, response): if response.error: future.set_exception(AuthError("Error response %s fetching %s" % (response.error, response.request.url))) return future.set_result(escape.json_decode(response.body)) def get_auth_http_client(self): return httpclient.AsyncHTTPClient() def _oauth_request_openid(self, access_token): return self._OAUTH_OPENID_URL + "access_token=" + access_token
Sina OAuth2封装(与QQ基本一致):
class SinaGraphOAuth2Mixin(OAuth2Mixin): _OAUTH_AUTHORIZE_URL = "https://api.weibo.com/oauth2/authorize?" _OAUTH_ACCESS_TOKEN_URL = "https://api.weibo.com/oauth2/access_token?" _OAUTH_NO_CALLBACKS = False _OAUTH_SINA_BASE_URL = "https://api.weibo.com/2" @_auth_return_future def get_authenticated_user(self, redirect_uri, client_id, client_secret, code, callback, extra_fields=None, extra_params=None): post_args = { "client_id" : client_id, "client_secret" : client_secret, "grant_type" : "authorization_code", "redirect_uri" : redirect_uri, "code" : code } self.sina_request( path="https://api.weibo.com/oauth2/access_token", callback=self.async_callback(self._on_access_token, callback, extra_fields), post_args = post_args, ) def _on_access_token(self, future, extra_fields, response): if response is None: future.set_result(None) return fields = set(['error_code', 'error', 'id', 'screen_name']) if extra_fields: fields.update(extra_fields) self.sina_request( path=self._OAUTH_SINA_BASE_URL+"/users/show.json", callback=self.async_callback(self._on_get_user_info, future, fields), access_token=response["access_token"], uid=response["uid"] ) def _on_get_user_info(self, future, fields, user): if user is None: future.set_result(None) return fieldmap = {} for field in fields: fieldmap[field] = user.get(field, "") future.set_result(fieldmap) @_auth_return_future def sina_request(self, path, callback, access_token=None, post_args=None, **args): url = path all_args = {} if access_token: all_args["access_token"] = access_token all_args.update(args) if all_args: url += "?" + urllib_parse.urlencode(all_args) callback = self.async_callback(self._on_sina_request, callback) http = self.get_auth_http_client() if post_args is not None: http.fetch(url, method="POST", body=urllib_parse.urlencode(post_args), callback=callback) else: http.fetch(url, callback=callback) def _on_sina_request(self, future, response): if response.error: future.set_exception(AuthError("Error response %s fetching %s" % (response.error, response.request.url))) return future.set_result(escape.json_decode(response.body)) def get_auth_http_client(self): return httpclient.AsyncHTTPClient()
使用(获取到用户信息直接登录):
class QQGraphLoginHandler(BaseHandler, QQGraphOAuth2Mixin): @tornado.web.asynchronous def get(self): my_url = (self.request.host.replace("localhost", "127.0.0.1") + "/qqlogin?next=" + tornado.escape.url_escape(self.get_argument("next", "/"))) if self.get_argument("code", False): self.get_authenticated_user( redirect_uri=my_url, client_id=self.settings["qq_api_key"], client_secret=self.settings["qq_api_secret"], code=self.get_argument("code"), extra_params={"grant_type": "authorization_code"}, callback=self._on_auth) return self.authorize_redirect(redirect_uri=my_url, client_id=self.settings["qq_api_key"], extra_params={"response_type": "code"}) def _on_auth(self, user): if not user: raise tornado.web.HTTPError(500, "qq auth failed") #user: openid, nickname uid = user.get("openid", 0) nick = user.get("nickname", uid)#default uid if user.get("ret", 0) or not uid: self.render('error.html', msg = user.get('msg', 'error')) else: ZQ_Account().login(uid, nick, "QQ", self._on_login) def _on_login(self, result, ex): if not ex: self.set_secure_cookie(settings.MGR_USER_COOKIE_KEY, json_encode(result) , expires_days = 1) self.redirect(self.get_argument("next", "/")) else: self.writeError(result)class SinaGraphLoginHandler(BaseHandler, SinaGraphOAuth2Mixin): @tornado.web.asynchronous def get(self): my_url = ("http://" + self.request.host.replace("localhost", "127.0.0.1") +#必须要http:// "/sinalogin") if self.get_argument("code", False): self.get_authenticated_user( redirect_uri=my_url, client_id=self.settings["sina_api_key"], client_secret=self.settings["sina_api_secret"], code=self.get_argument("code"), extra_params={"grant_type": "authorization_code"}, callback=self._on_auth) return self.authorize_redirect(redirect_uri=my_url, client_id=self.settings["sina_api_key"], extra_params={"response_type": "code"}) def _on_auth(self, user): if not user: raise tornado.web.HTTPError(500, "sina auth failed") #user: id, screen_name uid = user.get("id", 0) nick = user.get("screen_name", uid)#default uid if user.get("error_code", 0): self.render('error.html', msg = user.get('error')) else: ZQ_Account().login(uid, nick, "SINA", self._on_login) def _on_login(self, result, ex): if not ex: self.set_secure_cookie(settings.MGR_USER_COOKIE_KEY, json_encode(result) , expires_days = 1) self.redirect(self.get_argument("next", "/")) else: self.writeError(result)
QQ OAuth直接参考官方文档即可,很详细:
http://wiki.connect.qq.com/
Sina OAuth官方文档有点乱,可参考:
http://jingyan.baidu.com/article/455a99508c91c8a166277893.html
http://rsj217.diandian.com/post/2013-04-17/40050093587
0 0
- QQ、Sina等OAuth2.0接入
- Thinkphp3.2.3接入QQ登录OAuth2.0案例教程
- sina 微博 Oauth2.0接口
- sina 网站接入 oauth2授权错误 error:redirect_uri_mismatch
- js 接入qq sina授权登录
- OAuth2.0 Password接入说明
- 腾讯QQ第三方登录1:申请接入(OAuth2.0协议)
- OAuth2.0简介(QQ登录)
- Sina微博OAuth2框架解密
- 【QQ登录】OAuth2.0开发文档
- phpcms V9实现QQ登陆OAuth2.0
- ecshop qq互联登录OAuth2.0
- 新浪微博oauth2.0接入方法( java 版本)
- 腾讯空间 第三方接入(OAuth2.0/JS V2)
- QQ接入
- Android开发中,sina的OAuth授权问题:(三)OAuth2.0授权的实现
- 共享baidu.com,sohu.com,360.cn,qq.com,sina.com等二级域名
- QQ登陆OAuth2.0API(Wbm.QzoneV2API) V1.0.10.27
- POJ 1364 差分约束
- tapestry注释介绍Annotations
- iOS 各种控件默认高度
- 设计模式
- 查询数据表中的记录(SELECT)
- QQ、Sina等OAuth2.0接入
- LightRoom导入照片卡死
- 面向对象六大原则(六):开闭原则
- hdu 1028 Ignatius and the Princess III(整数划分)
- 使用 HTML5 canvas 进行 Web 绘图
- Android如何使用Handler
- BOOL、bool的区别 && NULL、0、nullptr的区别
- JVM调优参数说明
- VIM设置