diff --git a/DjangoBlog/settings.py b/DjangoBlog/settings.py index 569679d..6489a36 100644 --- a/DjangoBlog/settings.py +++ b/DjangoBlog/settings.py @@ -22,8 +22,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SECRET_KEY = '&3g0bdza#c%dm1lf%5gi&0-*53p3t0m*hmcvo29cn^$ji7je(c' # SECURITY WARNING: don't run with debug turned on in production! -#DEBUG = True -DEBUG = False +DEBUG = True +# DEBUG = False # ALLOWED_HOSTS = [] ALLOWED_HOSTS = ['www.lylinux.net', '127.0.0.1'] @@ -51,9 +51,9 @@ MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.gzip.GZipMiddleware', - #'django.middleware.cache.UpdateCacheMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', - #'django.middleware.cache.FetchFromCacheMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', @@ -208,6 +208,11 @@ OAHUTH = { 'appkey': os.environ.get('GOOGLE_APP_KEY'), 'appsecret': os.environ.get('GOOGLE_APP_SECRET'), 'callbackurl': 'http://www.lylinux.net/oauth/googleauthorize' + }, + 'github': { + 'appkey': os.environ.get('GITHUB_APP_KEY'), + 'appsecret': os.environ.get('GITHUB_APP_SECRET'), + 'callbackurl': 'http://www.lylinux.net/oauth/githubauthorize' } } diff --git a/blog/static/blog/css/oauth_style.css b/blog/static/blog/css/oauth_style.css new file mode 100644 index 0000000..8af78af --- /dev/null +++ b/blog/static/blog/css/oauth_style.css @@ -0,0 +1,305 @@ + +.icon-sn-google { + background-position: 0 -28px; +} + +.icon-sn-bg-google { + background-color: #4285f4; + background-position: 0 0; +} + +.fa-sn-google { + color: #4285f4; +} + +.icon-sn-github { + background-position: -28px -28px; +} + +.icon-sn-bg-github { + background-color: #333; + background-position: -28px 0; +} + +.fa-sn-github { + color: #333; +} + +.icon-sn-weibo { + background-position: -56px -28px; +} + +.icon-sn-bg-weibo { + background-color: #e90d24; + background-position: -56px 0; +} + +.fa-sn-weibo { + color: #e90d24; +} + +.icon-sn-qq { + background-position: -84px -28px; +} + +.icon-sn-bg-qq { + background-color: #0098e6; + background-position: -84px 0; +} + +.fa-sn-qq { + color: #0098e6; +} + +.icon-sn-twitter { + background-position: -112px -28px; +} + +.icon-sn-bg-twitter { + background-color: #50abf1; + background-position: -112px 0; +} + +.fa-sn-twitter { + color: #50abf1; +} + +.icon-sn-facebook { + background-position: -140px -28px; +} + +.icon-sn-bg-facebook { + background-color: #4862a3; + background-position: -140px 0; +} + +.fa-sn-facebook { + color: #4862a3; +} + +.icon-sn-renren { + background-position: -168px -28px; +} + +.icon-sn-bg-renren { + background-color: #197bc8; + background-position: -168px 0; +} + +.fa-sn-renren { + color: #197bc8; +} + +.icon-sn-tqq { + background-position: -196px -28px; +} + +.icon-sn-bg-tqq { + background-color: #1f9ed2; + background-position: -196px 0; +} + +.fa-sn-tqq { + color: #1f9ed2; +} + +.icon-sn-douban { + background-position: -224px -28px; +} + +.icon-sn-bg-douban { + background-color: #279738; + background-position: -224px 0; +} + +.fa-sn-douban { + color: #279738; +} + +.icon-sn-weixin { + background-position: -252px -28px; +} + +.icon-sn-bg-weixin { + background-color: #00b500; + background-position: -252px 0; +} + +.fa-sn-weixin { + color: #00b500; +} + +.icon-sn-dotted { + background-position: -280px -28px; +} + +.icon-sn-bg-dotted { + background-color: #eee; + background-position: -280px 0; +} + +.fa-sn-dotted { + color: #eee; +} + +.icon-sn-site { + background-position: -308px -28px; +} + +.icon-sn-bg-site { + background-color: #00b500; + background-position: -308px 0; +} + +.fa-sn-site { + color: #00b500; +} + +.icon-sn-linkedin { + background-position: -336px -28px; +} + +.icon-sn-bg-linkedin { + background-color: #0077b9; + background-position: -336px 0; +} + +.fa-sn-linkedin { + color: #0077b9; +} + +[class*=icon-sn-] { + display: inline-block; + background-image: url('../img/icon-sn.svg'); + background-repeat: no-repeat; + width: 28px; + height: 28px; + vertical-align: middle; + background-size: auto 56px; +} + +[class*=icon-sn-]:hover { + opacity: .8; + filter: alpha(opacity=80); +} + +.btn-sn-google { + background: #4285f4; +} + +.btn-sn-google:active, .btn-sn-google:focus, .btn-sn-google:hover { + background: #2a75f3; +} + +.btn-sn-github { + background: #333; +} + +.btn-sn-github:active, .btn-sn-github:focus, .btn-sn-github:hover { + background: #262626; +} + +.btn-sn-weibo { + background: #e90d24; +} + +.btn-sn-weibo:active, .btn-sn-weibo:focus, .btn-sn-weibo:hover { + background: #d10c20; +} + +.btn-sn-qq { + background: #0098e6; +} + +.btn-sn-qq:active, .btn-sn-qq:focus, .btn-sn-qq:hover { + background: #0087cd; +} + +.btn-sn-twitter { + background: #50abf1; +} + +.btn-sn-twitter:active, .btn-sn-twitter:focus, .btn-sn-twitter:hover { + background: #38a0ef; +} + +.btn-sn-facebook { + background: #4862a3; +} + +.btn-sn-facebook:active, .btn-sn-facebook:focus, .btn-sn-facebook:hover { + background: #405791; +} + +.btn-sn-renren { + background: #197bc8; +} + +.btn-sn-renren:active, .btn-sn-renren:focus, .btn-sn-renren:hover { + background: #166db1; +} + +.btn-sn-tqq { + background: #1f9ed2; +} + +.btn-sn-tqq:active, .btn-sn-tqq:focus, .btn-sn-tqq:hover { + background: #1c8dbc; +} + +.btn-sn-douban { + background: #279738; +} + +.btn-sn-douban:active, .btn-sn-douban:focus, .btn-sn-douban:hover { + background: #228330; +} + +.btn-sn-weixin { + background: #00b500; +} + +.btn-sn-weixin:active, .btn-sn-weixin:focus, .btn-sn-weixin:hover { + background: #009c00; +} + +.btn-sn-dotted { + background: #eee; +} + +.btn-sn-dotted:active, .btn-sn-dotted:focus, .btn-sn-dotted:hover { + background: #e1e1e1; +} + +.btn-sn-site { + background: #00b500; +} + +.btn-sn-site:active, .btn-sn-site:focus, .btn-sn-site:hover { + background: #009c00; +} + +.btn-sn-linkedin { + background: #0077b9; +} + +.btn-sn-linkedin:active, .btn-sn-linkedin:focus, .btn-sn-linkedin:hover { + background: #0067a0; +} + +[class*=btn-sn-], [class*=btn-sn-]:active, [class*=btn-sn-]:focus, [class*=btn-sn-]:hover { + border: none; + color: #fff; +} + +.btn-sn-more { + padding: 0; +} + +.btn-sn-more, .btn-sn-more:active, .btn-sn-more:hover { + box-shadow: none; +} + +[class*=btn-sn-] [class*=icon-sn-] { + background-color: transparent; +} \ No newline at end of file diff --git a/blog/static/blog/css/style.css b/blog/static/blog/css/style.css index fe85ae8..406ea31 100755 --- a/blog/static/blog/css/style.css +++ b/blog/static/blog/css/style.css @@ -2358,308 +2358,3 @@ li #reply-title { font: inherit; vertical-align: baseline; } - -.icon-sn-google { - background-position: 0 -28px; -} - -.icon-sn-bg-google { - background-color: #4285f4; - background-position: 0 0; -} - -.fa-sn-google { - color: #4285f4; -} - -.icon-sn-github { - background-position: -28px -28px; -} - -.icon-sn-bg-github { - background-color: #333; - background-position: -28px 0; -} - -.fa-sn-github { - color: #333; -} - -.icon-sn-weibo { - background-position: -56px -28px; -} - -.icon-sn-bg-weibo { - background-color: #e90d24; - background-position: -56px 0; -} - -.fa-sn-weibo { - color: #e90d24; -} - -.icon-sn-qq { - background-position: -84px -28px; -} - -.icon-sn-bg-qq { - background-color: #0098e6; - background-position: -84px 0; -} - -.fa-sn-qq { - color: #0098e6; -} - -.icon-sn-twitter { - background-position: -112px -28px; -} - -.icon-sn-bg-twitter { - background-color: #50abf1; - background-position: -112px 0; -} - -.fa-sn-twitter { - color: #50abf1; -} - -.icon-sn-facebook { - background-position: -140px -28px; -} - -.icon-sn-bg-facebook { - background-color: #4862a3; - background-position: -140px 0; -} - -.fa-sn-facebook { - color: #4862a3; -} - -.icon-sn-renren { - background-position: -168px -28px; -} - -.icon-sn-bg-renren { - background-color: #197bc8; - background-position: -168px 0; -} - -.fa-sn-renren { - color: #197bc8; -} - -.icon-sn-tqq { - background-position: -196px -28px; -} - -.icon-sn-bg-tqq { - background-color: #1f9ed2; - background-position: -196px 0; -} - -.fa-sn-tqq { - color: #1f9ed2; -} - -.icon-sn-douban { - background-position: -224px -28px; -} - -.icon-sn-bg-douban { - background-color: #279738; - background-position: -224px 0; -} - -.fa-sn-douban { - color: #279738; -} - -.icon-sn-weixin { - background-position: -252px -28px; -} - -.icon-sn-bg-weixin { - background-color: #00b500; - background-position: -252px 0; -} - -.fa-sn-weixin { - color: #00b500; -} - -.icon-sn-dotted { - background-position: -280px -28px; -} - -.icon-sn-bg-dotted { - background-color: #eee; - background-position: -280px 0; -} - -.fa-sn-dotted { - color: #eee; -} - -.icon-sn-site { - background-position: -308px -28px; -} - -.icon-sn-bg-site { - background-color: #00b500; - background-position: -308px 0; -} - -.fa-sn-site { - color: #00b500; -} - -.icon-sn-linkedin { - background-position: -336px -28px; -} - -.icon-sn-bg-linkedin { - background-color: #0077b9; - background-position: -336px 0; -} - -.fa-sn-linkedin { - color: #0077b9; -} - -[class*=icon-sn-] { - display: inline-block; - background-image: url('../img/icon-sn.svg'); - background-repeat: no-repeat; - width: 28px; - height: 28px; - vertical-align: middle; - background-size: auto 56px; -} - -[class*=icon-sn-]:hover { - opacity: .8; - filter: alpha(opacity=80); -} - -.btn-sn-google { - background: #4285f4; -} - -.btn-sn-google:active, .btn-sn-google:focus, .btn-sn-google:hover { - background: #2a75f3; -} - -.btn-sn-github { - background: #333; -} - -.btn-sn-github:active, .btn-sn-github:focus, .btn-sn-github:hover { - background: #262626; -} - -.btn-sn-weibo { - background: #e90d24; -} - -.btn-sn-weibo:active, .btn-sn-weibo:focus, .btn-sn-weibo:hover { - background: #d10c20; -} - -.btn-sn-qq { - background: #0098e6; -} - -.btn-sn-qq:active, .btn-sn-qq:focus, .btn-sn-qq:hover { - background: #0087cd; -} - -.btn-sn-twitter { - background: #50abf1; -} - -.btn-sn-twitter:active, .btn-sn-twitter:focus, .btn-sn-twitter:hover { - background: #38a0ef; -} - -.btn-sn-facebook { - background: #4862a3; -} - -.btn-sn-facebook:active, .btn-sn-facebook:focus, .btn-sn-facebook:hover { - background: #405791; -} - -.btn-sn-renren { - background: #197bc8; -} - -.btn-sn-renren:active, .btn-sn-renren:focus, .btn-sn-renren:hover { - background: #166db1; -} - -.btn-sn-tqq { - background: #1f9ed2; -} - -.btn-sn-tqq:active, .btn-sn-tqq:focus, .btn-sn-tqq:hover { - background: #1c8dbc; -} - -.btn-sn-douban { - background: #279738; -} - -.btn-sn-douban:active, .btn-sn-douban:focus, .btn-sn-douban:hover { - background: #228330; -} - -.btn-sn-weixin { - background: #00b500; -} - -.btn-sn-weixin:active, .btn-sn-weixin:focus, .btn-sn-weixin:hover { - background: #009c00; -} - -.btn-sn-dotted { - background: #eee; -} - -.btn-sn-dotted:active, .btn-sn-dotted:focus, .btn-sn-dotted:hover { - background: #e1e1e1; -} - -.btn-sn-site { - background: #00b500; -} - -.btn-sn-site:active, .btn-sn-site:focus, .btn-sn-site:hover { - background: #009c00; -} - -.btn-sn-linkedin { - background: #0077b9; -} - -.btn-sn-linkedin:active, .btn-sn-linkedin:focus, .btn-sn-linkedin:hover { - background: #0067a0; -} - -[class*=btn-sn-], [class*=btn-sn-]:active, [class*=btn-sn-]:focus, [class*=btn-sn-]:hover { - border: none; - color: #fff; -} - -.btn-sn-more { - padding: 0; -} - -.btn-sn-more, .btn-sn-more:active, .btn-sn-more:hover { - box-shadow: none; -} - -[class*=btn-sn-] [class*=icon-sn-] { - background-color: transparent; -} \ No newline at end of file diff --git a/oauth/oauthmanager.py b/oauth/oauthmanager.py index fce22d4..3fcd81f 100644 --- a/oauth/oauthmanager.py +++ b/oauth/oauthmanager.py @@ -14,12 +14,14 @@ """ from abc import ABCMeta, abstractmethod, abstractproperty +from django.conf import settings import requests import json import urllib.parse +from DjangoBlog.utils import logger -class BaseManager(metaclass=ABCMeta): +class BaseOauthManager(metaclass=ABCMeta): """获取用户授权""" AUTH_URL = None """获取token""" @@ -29,10 +31,7 @@ class BaseManager(metaclass=ABCMeta): '''icon图标名''' ICON_NAME = None - def __init__(self, client_id, client_secret, callback_url, access_token=None, openid=None): - self.client_id = client_id - self.client_secret = client_secret - self.callback_url = callback_url + def __init__(self, access_token=None, openid=None): self.access_token = access_token self.openid = openid @@ -65,14 +64,17 @@ class BaseManager(metaclass=ABCMeta): return rsp.text -class WBOauthManager(BaseManager): +class WBOauthManager(BaseOauthManager): AUTH_URL = 'https://api.weibo.com/oauth2/authorize' TOKEN_URL = 'https://api.weibo.com/oauth2/access_token' API_URL = 'https://api.weibo.com/2/users/show.json' + ICON_NAME = 'weibo' - def __init__(self, client_id, client_secret, callback_url, access_token=None, openid=None): - super(WBOauthManager, self).__init__(client_id=client_id, client_secret=client_secret, - callback_url=callback_url, access_token=access_token, openid=openid) + def __init__(self, access_token=None, openid=None): + self.client_id = settings.OAHUTH['sina']['appkey'] + self.client_secret = settings.OAHUTH['sina']['appsecret'] + self.callback_url = settings.OAHUTH['sina']['callbackurl'] + super(WBOauthManager, self).__init__(access_token=access_token, openid=openid) def get_authorization_url(self): params = { @@ -119,15 +121,17 @@ class WBOauthManager(BaseManager): print(rsp) -class GoogleOauthManager(BaseManager): +class GoogleOauthManager(BaseOauthManager): AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth' TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token' API_URL = 'https://www.googleapis.com/oauth2/v3/userinfo' ICON_NAME = 'google' - def __init__(self, client_id, client_secret, callback_url, access_token=None, openid=None): - super(GoogleOauthManager, self).__init__(client_id=client_id, client_secret=client_secret, - callback_url=callback_url, access_token=access_token, openid=openid) + def __init__(self, access_token=None, openid=None): + self.client_id = settings.OAHUTH['google']['appkey'] + self.client_secret = settings.OAHUTH['google']['appsecret'] + self.callback_url = settings.OAHUTH['google']['callbackurl'] + super(GoogleOauthManager, self).__init__(access_token=access_token, openid=openid) def get_authorization_url(self): params = { @@ -139,6 +143,60 @@ class GoogleOauthManager(BaseManager): url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote) return url + def get_access_token_by_code(self, code): + params = { + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'grant_type': 'authorization_code', + 'code': code, + + 'redirect_uri': self.callback_url + } + rsp = self.do_post(self.TOKEN_URL, params) + + obj = json.loads(rsp) + try: + self.access_token = str(obj['access_token']) + self.openid = str(obj['id_token']) + logger.info(self.ICON_NAME + ' oauth ' + rsp) + return self.access_token + except: + logger.info(self.ICON_NAME + ' oauth error ' + rsp) + return None + + def get_oauth_userinfo(self): + if not self.is_authorized: + return None + params = { + 'access_token': self.access_token + } + rsp = self.do_get(self.API_URL, params) + print(rsp) + return json.loads(rsp) + + +class GitHubOauthManager(BaseOauthManager): + AUTH_URL = 'https://github.com/login/oauth/authorize' + TOKEN_URL = 'https://github.com/login/oauth/access_token' + API_URL = 'https://api.github.com/user' + ICON_NAME = 'github' + + def __init__(self, access_token=None, openid=None): + self.client_id = settings.OAHUTH['github']['appkey'] + self.client_secret = settings.OAHUTH['github']['appsecret'] + self.callback_url = settings.OAHUTH['github']['callbackurl'] + super(GitHubOauthManager, self).__init__(access_token=access_token, openid=openid) + + def get_authorization_url(self): + params = { + 'client_id': self.client_id, + 'response_type': 'code', + 'redirect_uri': self.callback_url, + 'scope': 'user:email', + } + url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote) + return url + def get_access_token_by_code(self, code): params = { 'client_id': self.client_id, diff --git a/oauth/templatetags/__init__.py b/oauth/templatetags/__init__.py new file mode 100644 index 0000000..a8d9fd4 --- /dev/null +++ b/oauth/templatetags/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +""" +@version: ?? +@author: liangliangyy +@license: MIT Licence +@contact: liangliangyy@gmail.com +@site: https://www.lylinux.org/ +@software: PyCharm +@file: __init__.py +@time: 2017/3/4 下午3:22 +""" \ No newline at end of file diff --git a/oauth/templatetags/oauth_tags.py b/oauth/templatetags/oauth_tags.py new file mode 100644 index 0000000..26da1f7 --- /dev/null +++ b/oauth/templatetags/oauth_tags.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +""" +@version: ?? +@author: liangliangyy +@license: MIT Licence +@contact: liangliangyy@gmail.com +@site: https://www.lylinux.org/ +@software: PyCharm +@file: oauth_tags.py +@time: 2017/3/4 下午3:22 +""" +from oauth.oauthmanager import * + +from django import template +from django.conf import settings + +register = template.Library() + + +@register.inclusion_tag('oauth/oauth_applications.html') +def load_oauth_applications(): + applications = BaseOauthManager.__subclasses__() + apps = [] + for application in applications: + app = application() + icon = app.ICON_NAME + authorizeurl = app.get_authorization_url() + apps.append((icon, authorizeurl)) + return { + 'apps': apps + } diff --git a/oauth/views.py b/oauth/views.py index a88051f..d9a0d81 100644 --- a/oauth/views.py +++ b/oauth/views.py @@ -3,9 +3,10 @@ from django.shortcuts import render # Create your views here. from .oauthmanager import WBOauthManager, GoogleOauthManager from django.conf import settings -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseRedirect from django.contrib.auth import get_user_model from .models import GoogleUserInfo +from django.contrib.auth import login def wbauthorize(request, sitename): @@ -27,33 +28,31 @@ def wboauthurl(request): def googleoauthurl(request): - manager = GoogleOauthManager(client_id=settings.OAHUTH['google']['appkey'], - client_secret=settings.OAHUTH['google']['appsecret'], - callback_url=settings.OAHUTH['google']['callbackurl']) + manager = GoogleOauthManager() url = manager.get_authorization_url() return HttpResponse(url) def googleauthorize(request): - manager = GoogleOauthManager(client_id=settings.OAHUTH['google']['appkey'], - client_secret=settings.OAHUTH['google']['appsecret'], - callback_url=settings.OAHUTH['google']['callbackurl']) + manager = GoogleOauthManager() code = request.GET.get('code', None) rsp = manager.get_access_token_by_code(code) - print(rsp) + if not rsp: + return HttpResponseRedirect(manager.get_authorization_url()) user = manager.get_oauth_userinfo() if user: email = user['email'] - author = get_user_model().objects.get(email=email) - if not author: - author = get_user_model().objects.create_user(username=user["name"], email=email, password=None, - nikename=user["name"]) - if not GoogleUserInfo.objects.filter(author_id=author.pk): - userinfo = GoogleUserInfo() - userinfo.author = author - userinfo.picture = user["picture"] - userinfo.token = manager.access_token - userinfo.openid = manager.openid - userinfo.nikename = user["name"] - userinfo.save() - return HttpResponse(rsp) + if email: + author = get_user_model().objects.get(email=email) + if not author: + author = get_user_model().objects.create_user(username=user["name"], email=email) + if not GoogleUserInfo.objects.filter(author_id=author.pk): + userinfo = GoogleUserInfo() + userinfo.author = author + userinfo.picture = user["picture"] + userinfo.token = manager.access_token + userinfo.openid = manager.openid + userinfo.nikename = user["name"] + userinfo.save() + login(request, author) + return HttpResponseRedirect('/') diff --git a/templates/account/login.html b/templates/account/login.html index 10800ba..57c55a3 100644 --- a/templates/account/login.html +++ b/templates/account/login.html @@ -28,7 +28,8 @@ Stay signed in - + {% load oauth_tags %} + {% load_oauth_applications %} diff --git a/templates/oauth/oauth_applications.html b/templates/oauth/oauth_applications.html new file mode 100644 index 0000000..c876343 --- /dev/null +++ b/templates/oauth/oauth_applications.html @@ -0,0 +1,7 @@ +
+ {% for icon,url in apps %} + + + + {% endfor %} +
\ No newline at end of file diff --git a/templates/share_layout/base.html b/templates/share_layout/base.html index 7eff3d5..3ee1107 100644 --- a/templates/share_layout/base.html +++ b/templates/share_layout/base.html @@ -32,6 +32,7 @@ {% compress css %} + {% comment %}{% endcomment %} - +