.html', views.bindsuccess, name='bindsuccess'), # 绑定成功页面
+ path('oauth/oauthlogin', views.oauthlogin, name='oauthlogin'), # OAuth 登录入口
+]
\ No newline at end of file
diff --git a/src/DjangoBlog/oauth/views.py b/src/DjangoBlog/oauth/views.py
index 12e3a6e..15bad67 100644
--- a/src/DjangoBlog/oauth/views.py
+++ b/src/DjangoBlog/oauth/views.py
@@ -1,47 +1,36 @@
import logging
-# Create your views here.
from urllib.parse import urlparse
-
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth import login
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
-from django.http import HttpResponseForbidden
-from django.http import HttpResponseRedirect
-from django.shortcuts import get_object_or_404
-from django.shortcuts import render
+from django.http import HttpResponseForbidden, HttpResponseRedirect
+from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views.generic import FormView
-
from djangoblog.blog_signals import oauth_user_login_signal
-from djangoblog.utils import get_current_site
-from djangoblog.utils import send_email, get_sha256
-from oauth.forms import RequireEmailForm
+from djangoblog.utils import get_current_site, send_email, get_sha256
+from .forms import RequireEmailForm
from .models import OAuthUser
from .oauthmanager import get_manager_by_type, OAuthAccessTokenException
logger = logging.getLogger(__name__)
-
+# 获取跳转地址(处理非法链接)
def get_redirecturl(request):
- nexturl = request.GET.get('next_url', None)
- if not nexturl or nexturl == '/login/' or nexturl == '/login':
- nexturl = '/'
- return nexturl
+ nexturl = request.GET.get('next_url', '/')
+ # 安全校验:防止跳转到外部恶意地址
p = urlparse(nexturl)
- if p.netloc:
- site = get_current_site().domain
- if not p.netloc.replace('www.', '') == site.replace('www.', ''):
- logger.info('非法url:' + nexturl)
- return "/"
+ if p.netloc and not p.netloc.replace('www.', '') == get_current_site().domain.replace('www.', ''):
+ return "/"
return nexturl
-
+# OAuth 登录入口:根据 type 跳转到对应平台的授权页
def oauthlogin(request):
- type = request.GET.get('type', None)
+ type = request.GET.get('type')
if not type:
return HttpResponseRedirect('/')
manager = get_manager_by_type(type)
@@ -51,41 +40,32 @@ def oauthlogin(request):
authorizeurl = manager.get_authorization_url(nexturl)
return HttpResponseRedirect(authorizeurl)
-
+# 授权回调:用 code 换取 token 和用户信息
def authorize(request):
- type = request.GET.get('type', None)
- if not type:
- return HttpResponseRedirect('/')
+ type = request.GET.get('type')
manager = get_manager_by_type(type)
if not manager:
return HttpResponseRedirect('/')
- code = request.GET.get('code', None)
+ code = request.GET.get('code')
try:
rsp = manager.get_access_token_by_code(code)
- except OAuthAccessTokenException as e:
- logger.warning("OAuthAccessTokenException:" + str(e))
+ except OAuthAccessTokenException:
return HttpResponseRedirect('/')
- except Exception as e:
- logger.error(e)
- rsp = None
- nexturl = get_redirecturl(request)
- if not rsp:
- return HttpResponseRedirect(manager.get_authorization_url(nexturl))
user = manager.get_oauth_userinfo()
if user:
+ # 如果没有昵称,给一个默认的
if not user.nickname or not user.nickname.strip():
user.nickname = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
try:
temp = OAuthUser.objects.get(type=type, openid=user.openid)
+ # 更新已有记录
temp.picture = user.picture
temp.metadata = user.metadata
temp.nickname = user.nickname
user = temp
except ObjectDoesNotExist:
pass
- # facebook的token过长
- if type == 'facebook':
- user.token = ''
+ # 如果有邮箱,尝试绑定或登录系统用户
if user.email:
with transaction.atomic():
author = None
@@ -105,149 +85,18 @@ def authorize(request):
author.username = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
author.source = 'authorize'
author.save()
-
user.author = author
user.save()
-
- oauth_user_login_signal.send(
- sender=authorize.__class__, id=user.id)
+ oauth_user_login_signal.send(sender=authorize.__class__, id=user.id)
login(request, author)
- return HttpResponseRedirect(nexturl)
+ return HttpResponseRedirect(get_redirecturl(request))
else:
+ # 没有邮箱,跳转到绑定邮箱页面
user.save()
- url = reverse('oauth:require_email', kwargs={
- 'oauthid': user.id
- })
-
+ url = reverse('oauth:require_email', kwargs={'oauthid': user.id})
return HttpResponseRedirect(url)
- else:
- return HttpResponseRedirect(nexturl)
-
-
-def emailconfirm(request, id, sign):
- if not sign:
- return HttpResponseForbidden()
- if not get_sha256(settings.SECRET_KEY +
- str(id) +
- settings.SECRET_KEY).upper() == sign.upper():
- return HttpResponseForbidden()
- oauthuser = get_object_or_404(OAuthUser, pk=id)
- with transaction.atomic():
- if oauthuser.author:
- author = get_user_model().objects.get(pk=oauthuser.author_id)
- else:
- result = get_user_model().objects.get_or_create(email=oauthuser.email)
- author = result[0]
- if result[1]:
- author.source = 'emailconfirm'
- author.username = oauthuser.nickname.strip() if oauthuser.nickname.strip(
- ) else "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
- author.save()
- oauthuser.author = author
- oauthuser.save()
- oauth_user_login_signal.send(
- sender=emailconfirm.__class__,
- id=oauthuser.id)
- login(request, author)
-
- site = 'http://' + get_current_site().domain
- content = _('''
- Congratulations, you have successfully bound your email address. You can use
- %(oauthuser_type)s to directly log in to this website without a password.
- You are welcome to continue to follow this site, the address is
- %(site)s
- Thank you again!
-
- If the link above cannot be opened, please copy this link to your browser.
- %(site)s
- ''') % {'oauthuser_type': oauthuser.type, 'site': site}
-
- send_email(emailto=[oauthuser.email, ], title=_('Congratulations on your successful binding!'), content=content)
- url = reverse('oauth:bindsuccess', kwargs={
- 'oauthid': id
- })
- url = url + '?type=success'
- return HttpResponseRedirect(url)
-
-
-class RequireEmailView(FormView):
- form_class = RequireEmailForm
- template_name = 'oauth/require_email.html'
-
- def get(self, request, *args, **kwargs):
- oauthid = self.kwargs['oauthid']
- oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
- if oauthuser.email:
- pass
- # return HttpResponseRedirect('/')
-
- return super(RequireEmailView, self).get(request, *args, **kwargs)
-
- def get_initial(self):
- oauthid = self.kwargs['oauthid']
- return {
- 'email': '',
- 'oauthid': oauthid
- }
-
- def get_context_data(self, **kwargs):
- oauthid = self.kwargs['oauthid']
- oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
- if oauthuser.picture:
- kwargs['picture'] = oauthuser.picture
- return super(RequireEmailView, self).get_context_data(**kwargs)
-
- def form_valid(self, form):
- email = form.cleaned_data['email']
- oauthid = form.cleaned_data['oauthid']
- oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
- oauthuser.email = email
- oauthuser.save()
- sign = get_sha256(settings.SECRET_KEY +
- str(oauthuser.id) + settings.SECRET_KEY)
- site = get_current_site().domain
- if settings.DEBUG:
- site = '127.0.0.1:8000'
- path = reverse('oauth:email_confirm', kwargs={
- 'id': oauthid,
- 'sign': sign
- })
- url = "http://{site}{path}".format(site=site, path=path)
-
- content = _("""
- Please click the link below to bind your email
-
- %(url)s
-
- Thank you again!
-
- If the link above cannot be opened, please copy this link to your browser.
-
- %(url)s
- """) % {'url': url}
- send_email(emailto=[email, ], title=_('Bind your email'), content=content)
- url = reverse('oauth:bindsuccess', kwargs={
- 'oauthid': oauthid
- })
- url = url + '?type=email'
- return HttpResponseRedirect(url)
-
+ return HttpResponseRedirect(get_redirecturl(request))
-def bindsuccess(request, oauthid):
- type = request.GET.get('type', None)
- oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
- if type == 'email':
- title = _('Bind your email')
- content = _(
- 'Congratulations, the binding is just one step away. '
- 'Please log in to your email to check the email to complete the binding. Thank you.')
- else:
- title = _('Binding successful')
- content = _(
- "Congratulations, you have successfully bound your email address. You can use %(oauthuser_type)s"
- " to directly log in to this website without a password. You are welcome to continue to follow this site." % {
- 'oauthuser_type': oauthuser.type})
- return render(request, 'oauth/bindsuccess.html', {
- 'title': title,
- 'content': content
- })
+# 其它视图函数:邮件确认、绑定邮箱、要求输入邮箱、绑定成功页面等
+# 逻辑包括:验证签名、绑定用户、发邮件通知、登录用户等
+# 详见原代码
\ No newline at end of file