mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-17 07:41:26 +00:00
BIN
media/img/weixin.png
Normal file
BIN
media/img/weixin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@@ -45,6 +45,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
ENABLE_FILE_SCAN = False
|
ENABLE_FILE_SCAN = False
|
||||||
from seahub.work_weixin.settings import ENABLE_WORK_WEIXIN
|
from seahub.work_weixin.settings import ENABLE_WORK_WEIXIN
|
||||||
|
from seahub.weixin.settings import ENABLE_WEIXIN
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from seahub.settings import SIDE_NAV_FOOTER_CUSTOM_HTML
|
from seahub.settings import SIDE_NAV_FOOTER_CUSTOM_HTML
|
||||||
@@ -111,6 +112,7 @@ def base(request):
|
|||||||
'org': org,
|
'org': org,
|
||||||
'site_name': get_site_name(),
|
'site_name': get_site_name(),
|
||||||
'enable_signup': config.ENABLE_SIGNUP,
|
'enable_signup': config.ENABLE_SIGNUP,
|
||||||
|
'enable_weixin': ENABLE_WEIXIN,
|
||||||
'max_file_name': MAX_FILE_NAME,
|
'max_file_name': MAX_FILE_NAME,
|
||||||
'has_file_search': HAS_FILE_SEARCH,
|
'has_file_search': HAS_FILE_SEARCH,
|
||||||
'show_repo_download_button': SHOW_REPO_DOWNLOAD_BUTTON,
|
'show_repo_download_button': SHOW_REPO_DOWNLOAD_BUTTON,
|
||||||
|
@@ -5,6 +5,7 @@ from seahub.base.accounts import User
|
|||||||
from registration.models import (notify_admins_on_activate_request,
|
from registration.models import (notify_admins_on_activate_request,
|
||||||
notify_admins_on_register_complete)
|
notify_admins_on_register_complete)
|
||||||
from seahub.work_weixin.settings import ENABLE_WORK_WEIXIN
|
from seahub.work_weixin.settings import ENABLE_WORK_WEIXIN
|
||||||
|
from seahub.weixin.settings import ENABLE_WEIXIN
|
||||||
from seahub.dingtalk.settings import ENABLE_DINGTALK
|
from seahub.dingtalk.settings import ENABLE_DINGTALK
|
||||||
|
|
||||||
class OauthRemoteUserBackend(RemoteUserBackend):
|
class OauthRemoteUserBackend(RemoteUserBackend):
|
||||||
@@ -28,6 +29,12 @@ class OauthRemoteUserBackend(RemoteUserBackend):
|
|||||||
create_unknown_user = getattr(settings, 'WORK_WEIXIN_OAUTH_CREATE_UNKNOWN_USER', True)
|
create_unknown_user = getattr(settings, 'WORK_WEIXIN_OAUTH_CREATE_UNKNOWN_USER', True)
|
||||||
activate_after_creation = getattr(settings, 'WORK_WEIXIN_OAUTH_ACTIVATE_USER_AFTER_CREATION', True)
|
activate_after_creation = getattr(settings, 'WORK_WEIXIN_OAUTH_ACTIVATE_USER_AFTER_CREATION', True)
|
||||||
|
|
||||||
|
if ENABLE_WEIXIN:
|
||||||
|
from seahub.weixin.settings import WEIXIN_OAUTH_CREATE_UNKNOWN_USER, \
|
||||||
|
WEIXIN_OAUTH_ACTIVATE_USER_AFTER_CREATION
|
||||||
|
create_unknown_user = WEIXIN_OAUTH_CREATE_UNKNOWN_USER
|
||||||
|
activate_after_creation = WEIXIN_OAUTH_ACTIVATE_USER_AFTER_CREATION
|
||||||
|
|
||||||
if ENABLE_DINGTALK:
|
if ENABLE_DINGTALK:
|
||||||
from seahub.dingtalk.settings import DINGTALK_QR_CONNECT_CREATE_UNKNOWN_USER, \
|
from seahub.dingtalk.settings import DINGTALK_QR_CONNECT_CREATE_UNKNOWN_USER, \
|
||||||
DINGTALK_QR_CONNECT_ACTIVATE_USER_AFTER_CREATION
|
DINGTALK_QR_CONNECT_ACTIVATE_USER_AFTER_CREATION
|
||||||
|
@@ -279,6 +279,9 @@ ENABLE_WATERMARK = False
|
|||||||
# enable work weixin
|
# enable work weixin
|
||||||
ENABLE_WORK_WEIXIN = False
|
ENABLE_WORK_WEIXIN = False
|
||||||
|
|
||||||
|
# enable weixin
|
||||||
|
ENABLE_WEIXIN = False
|
||||||
|
|
||||||
# enable dingtalk
|
# enable dingtalk
|
||||||
ENABLE_DINGTALK = False
|
ENABLE_DINGTALK = False
|
||||||
|
|
||||||
@@ -888,7 +891,7 @@ if ENABLE_REMOTE_USER_AUTHENTICATION:
|
|||||||
MIDDLEWARE_CLASSES += ('seahub.auth.middleware.SeafileRemoteUserMiddleware',)
|
MIDDLEWARE_CLASSES += ('seahub.auth.middleware.SeafileRemoteUserMiddleware',)
|
||||||
AUTHENTICATION_BACKENDS += ('seahub.auth.backends.SeafileRemoteUserBackend',)
|
AUTHENTICATION_BACKENDS += ('seahub.auth.backends.SeafileRemoteUserBackend',)
|
||||||
|
|
||||||
if ENABLE_OAUTH or ENABLE_WORK_WEIXIN or ENABLE_DINGTALK:
|
if ENABLE_OAUTH or ENABLE_WORK_WEIXIN or ENABLE_WEIXIN or ENABLE_DINGTALK:
|
||||||
AUTHENTICATION_BACKENDS += ('seahub.oauth.backends.OauthRemoteUserBackend',)
|
AUTHENTICATION_BACKENDS += ('seahub.oauth.backends.OauthRemoteUserBackend',)
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
|
@@ -16,7 +16,11 @@
|
|||||||
{% block extra_script %}{{block.super}}
|
{% block extra_script %}{{block.super}}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#personal').on('click', function() {
|
$('#personal').on('click', function() {
|
||||||
|
{% if enable_weixin %}
|
||||||
|
location.href = "{% url 'weixin_oauth_login'%}";
|
||||||
|
{% else %}
|
||||||
location.href = "{% url 'registration_register'%}";
|
location.href = "{% url 'registration_register'%}";
|
||||||
|
{% endif %}
|
||||||
});
|
});
|
||||||
$('#org').on('click', function() {
|
$('#org').on('click', function() {
|
||||||
location.href = "{% url 'org_register'%}";
|
location.href = "{% url 'org_register'%}";
|
||||||
|
@@ -74,6 +74,15 @@ html, body, #wrapper { height:100%; }
|
|||||||
<a id="sso" href="#" class="normal">{% trans "Single Sign-On" %}</a>
|
<a id="sso" href="#" class="normal">{% trans "Single Sign-On" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enable_weixin %}
|
||||||
|
<div>
|
||||||
|
{% trans "Login with: " %}
|
||||||
|
<a href="{% url "weixin_oauth_login" %}">
|
||||||
|
<img src="{{MEDIA_URL}}img/weixin.png" width="32" alt="" title="{% if LANGUAGE_CODE == 'zh-cn' %}微信{% else %}WeChat{% endif %}" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="login-panel-bottom-container">
|
<div class="login-panel-bottom-container">
|
||||||
{% if enable_signup %}
|
{% if enable_signup %}
|
||||||
<a href="{{ signup_url }}" class="normal fleft" id="sign-up">{% trans "Signup" %}</a>
|
<a href="{{ signup_url }}" class="normal fleft" id="sign-up">{% trans "Signup" %}</a>
|
||||||
|
@@ -603,6 +603,7 @@ urlpatterns = [
|
|||||||
url(r'^terms/', include('termsandconditions.urls')),
|
url(r'^terms/', include('termsandconditions.urls')),
|
||||||
url(r'^published/', include('seahub.wiki.urls', app_name='wiki', namespace='wiki')),
|
url(r'^published/', include('seahub.wiki.urls', app_name='wiki', namespace='wiki')),
|
||||||
url(r'^work-weixin/', include('seahub.work_weixin.urls')),
|
url(r'^work-weixin/', include('seahub.work_weixin.urls')),
|
||||||
|
url(r'^weixin/', include('seahub.weixin.urls')),
|
||||||
# Must specify a namespace if specifying app_name.
|
# Must specify a namespace if specifying app_name.
|
||||||
url(r'^drafts/', include('seahub.drafts.urls', app_name='drafts', namespace='drafts')),
|
url(r'^drafts/', include('seahub.drafts.urls', app_name='drafts', namespace='drafts')),
|
||||||
|
|
||||||
|
@@ -62,6 +62,8 @@ from seahub.wopi.settings import ENABLE_OFFICE_WEB_APP
|
|||||||
from seahub.onlyoffice.settings import ENABLE_ONLYOFFICE
|
from seahub.onlyoffice.settings import ENABLE_ONLYOFFICE
|
||||||
from seahub.constants import HASH_URLS, PERMISSION_READ
|
from seahub.constants import HASH_URLS, PERMISSION_READ
|
||||||
|
|
||||||
|
from seahub.weixin.settings import ENABLE_WEIXIN
|
||||||
|
|
||||||
LIBRARY_TEMPLATES = getattr(settings, 'LIBRARY_TEMPLATES', {})
|
LIBRARY_TEMPLATES = getattr(settings, 'LIBRARY_TEMPLATES', {})
|
||||||
CUSTOM_NAV_ITEMS = getattr(settings, 'CUSTOM_NAV_ITEMS', '')
|
CUSTOM_NAV_ITEMS = getattr(settings, 'CUSTOM_NAV_ITEMS', '')
|
||||||
|
|
||||||
@@ -1112,6 +1114,7 @@ def choose_register(request):
|
|||||||
login_bg_image_path = get_login_bg_image_path()
|
login_bg_image_path = get_login_bg_image_path()
|
||||||
|
|
||||||
return render(request, 'choose_register.html', {
|
return render(request, 'choose_register.html', {
|
||||||
|
'enable_weixin': ENABLE_WEIXIN,
|
||||||
'login_bg_image_path': login_bg_image_path
|
'login_bg_image_path': login_bg_image_path
|
||||||
})
|
})
|
||||||
|
|
||||||
|
0
seahub/weixin/__init__.py
Normal file
0
seahub/weixin/__init__.py
Normal file
19
seahub/weixin/settings.py
Normal file
19
seahub/weixin/settings.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Copyright (c) 2012-2019 Seafile Ltd.
|
||||||
|
# encoding: utf-8
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
ENABLE_WEIXIN = getattr(settings, 'ENABLE_WEIXIN', False)
|
||||||
|
WEIXIN_OAUTH_APP_ID = getattr(settings, 'WEIXIN_OAUTH_APP_ID', '')
|
||||||
|
WEIXIN_OAUTH_APP_SECRET = getattr(settings, 'WEIXIN_OAUTH_APP_SECRET', '')
|
||||||
|
|
||||||
|
WEIXIN_OAUTH_SCOPE = getattr(settings, 'WEIXIN_OAUTH_SCOPE', 'snsapi_login')
|
||||||
|
WEIXIN_OAUTH_RESPONSE_TYPE = getattr(settings, 'WEIXIN_OAUTH_RESPONSE_TYPE', 'code')
|
||||||
|
WEIXIN_OAUTH_QR_CONNECT_URL = getattr(settings, 'WEIXIN_OAUTH_QR_CONNECT_URL', 'https://open.weixin.qq.com/connect/qrconnect')
|
||||||
|
|
||||||
|
WEIXIN_OAUTH_GRANT_TYPE = getattr(settings, 'WEIXIN_OAUTH_GRANT_TYPE', 'authorization_code')
|
||||||
|
WEIXIN_OAUTH_ACCESS_TOKEN_URL = getattr(settings, 'WEIXIN_OAUTH_ACCESS_TOKEN_URL', 'https://api.weixin.qq.com/sns/oauth2/access_token')
|
||||||
|
|
||||||
|
WEIXIN_OAUTH_USER_INFO_URL = getattr(settings, 'WEIXIN_OAUTH_USER_INFO_URL', 'https://api.weixin.qq.com/sns/userinfo')
|
||||||
|
|
||||||
|
WEIXIN_OAUTH_CREATE_UNKNOWN_USER = getattr(settings, 'WEIXIN_OAUTH_CREATE_UNKNOWN_USER', True)
|
||||||
|
WEIXIN_OAUTH_ACTIVATE_USER_AFTER_CREATION = getattr(settings, 'WEIXIN_OAUTH_ACTIVATE_USER_AFTER_CREATION', True)
|
10
seahub/weixin/urls.py
Normal file
10
seahub/weixin/urls.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2012-2019 Seafile Ltd.
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
from seahub.weixin.views import weixin_oauth_login, weixin_oauth_callback
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'oauth-login/$', weixin_oauth_login, name='weixin_oauth_login'),
|
||||||
|
url(r'oauth-callback/$', weixin_oauth_callback, name='weixin_oauth_callback'),
|
||||||
|
]
|
138
seahub/weixin/views.py
Normal file
138
seahub/weixin/views.py
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
import urllib
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from seahub.api2.utils import get_api_token
|
||||||
|
|
||||||
|
from seahub import auth
|
||||||
|
from seahub.base.accounts import User
|
||||||
|
from seahub.avatar.models import Avatar
|
||||||
|
from seahub.profile.models import Profile
|
||||||
|
from seahub.utils import render_error, get_site_scheme_and_netloc
|
||||||
|
from seahub.utils.auth import gen_user_virtual_id
|
||||||
|
from seahub.auth.models import SocialAuthUser
|
||||||
|
|
||||||
|
from seahub.weixin.settings import ENABLE_WEIXIN, \
|
||||||
|
WEIXIN_OAUTH_APP_ID, WEIXIN_OAUTH_APP_SECRET, \
|
||||||
|
WEIXIN_OAUTH_SCOPE, WEIXIN_OAUTH_RESPONSE_TYPE, WEIXIN_OAUTH_QR_CONNECT_URL, \
|
||||||
|
WEIXIN_OAUTH_GRANT_TYPE, WEIXIN_OAUTH_ACCESS_TOKEN_URL, \
|
||||||
|
WEIXIN_OAUTH_USER_INFO_URL
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
|
||||||
|
|
||||||
|
def weixin_oauth_login(request):
|
||||||
|
|
||||||
|
if not ENABLE_WEIXIN:
|
||||||
|
return render_error(request, _('Error, please contact administrator.'))
|
||||||
|
|
||||||
|
state = str(uuid.uuid4())
|
||||||
|
request.session['weixin_oauth_login_state'] = state
|
||||||
|
request.session['weixin_oauth_login_redirect'] = request.GET.get(auth.REDIRECT_FIELD_NAME, '/')
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'appid': WEIXIN_OAUTH_APP_ID,
|
||||||
|
'redirect_uri': get_site_scheme_and_netloc() + reverse('weixin_oauth_callback'),
|
||||||
|
'response_type': WEIXIN_OAUTH_RESPONSE_TYPE,
|
||||||
|
'scope': WEIXIN_OAUTH_SCOPE,
|
||||||
|
'state': state,
|
||||||
|
}
|
||||||
|
url = WEIXIN_OAUTH_QR_CONNECT_URL + '?' + urllib.parse.urlencode(data)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
def weixin_oauth_callback(request):
|
||||||
|
|
||||||
|
if not ENABLE_WEIXIN:
|
||||||
|
return render_error(request, _('Error, please contact administrator.'))
|
||||||
|
|
||||||
|
state = request.GET.get('state', '')
|
||||||
|
if not state or state != request.session.get('weixin_oauth_login_state', ''):
|
||||||
|
logger.error('invalid state')
|
||||||
|
return render_error(request, _('Error, please contact administrator.'))
|
||||||
|
|
||||||
|
# get access_token and user openid
|
||||||
|
parameters = {
|
||||||
|
'appid': WEIXIN_OAUTH_APP_ID,
|
||||||
|
'secret': WEIXIN_OAUTH_APP_SECRET,
|
||||||
|
'code': request.GET.get('code'),
|
||||||
|
'grant_type': WEIXIN_OAUTH_GRANT_TYPE,
|
||||||
|
}
|
||||||
|
|
||||||
|
access_token_url = WEIXIN_OAUTH_ACCESS_TOKEN_URL + '?' + urllib.parse.urlencode(parameters)
|
||||||
|
access_token_json = requests.get(access_token_url).json()
|
||||||
|
|
||||||
|
openid = access_token_json.get('openid', '')
|
||||||
|
access_token = access_token_json.get('access_token', '')
|
||||||
|
if not access_token or not openid:
|
||||||
|
logger.error('invalid access_token or openid')
|
||||||
|
logger.error(access_token_url)
|
||||||
|
logger.error(access_token_json)
|
||||||
|
return render_error(request, _('Error, please contact administrator.'))
|
||||||
|
|
||||||
|
# login user in
|
||||||
|
auth_user = SocialAuthUser.objects.get_by_provider_and_uid('weixin', openid)
|
||||||
|
if auth_user:
|
||||||
|
email = auth_user.username
|
||||||
|
else:
|
||||||
|
email = gen_user_virtual_id()
|
||||||
|
SocialAuthUser.objects.add(email, 'weixin', openid)
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = auth.authenticate(remote_user=email)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
user = None
|
||||||
|
|
||||||
|
if not user or not user.is_active:
|
||||||
|
return render_error(request, _('User %s not found or inactive.') % email)
|
||||||
|
|
||||||
|
request.user = user
|
||||||
|
auth.login(request, user)
|
||||||
|
|
||||||
|
# get user profile info
|
||||||
|
parameters = {
|
||||||
|
'access_token': access_token,
|
||||||
|
'openid': openid,
|
||||||
|
}
|
||||||
|
user_info_url = WEIXIN_OAUTH_USER_INFO_URL + '?' + urllib.parse.urlencode(parameters)
|
||||||
|
user_info_resp = requests.get(user_info_url).json()
|
||||||
|
|
||||||
|
name = user_info_resp['nickname'] if 'nickname' in user_info_resp else ''
|
||||||
|
name = name.encode('raw_unicode_escape').decode('utf-8')
|
||||||
|
if name:
|
||||||
|
|
||||||
|
profile = Profile.objects.get_profile_by_user(email)
|
||||||
|
if not profile:
|
||||||
|
profile = Profile(user=email)
|
||||||
|
|
||||||
|
profile.nickname = name.strip()
|
||||||
|
profile.save()
|
||||||
|
|
||||||
|
avatar_url = user_info_resp['headimgurl'] if 'headimgurl' in user_info_resp else ''
|
||||||
|
try:
|
||||||
|
image_name = 'dingtalk_avatar'
|
||||||
|
image_file = requests.get(avatar_url).content
|
||||||
|
avatar = Avatar.objects.filter(emailuser=email, primary=True).first()
|
||||||
|
avatar = avatar or Avatar(emailuser=email, primary=True)
|
||||||
|
avatar_file = ContentFile(image_file)
|
||||||
|
avatar_file.name = image_name
|
||||||
|
avatar.avatar = avatar_file
|
||||||
|
avatar.save()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
# generate auth token for Seafile client
|
||||||
|
api_token = get_api_token(request)
|
||||||
|
|
||||||
|
# redirect user to home page
|
||||||
|
response = HttpResponseRedirect(request.session['weixin_oauth_login_redirect'])
|
||||||
|
response.set_cookie('seahub_auth', email + '@' + api_token.key)
|
||||||
|
return response
|
Reference in New Issue
Block a user