[Update] 修改注册流程

pull/828/merge
ibuler 2017-12-25 12:22:49 +08:00
parent 8b081cd6b0
commit f4beccddae
11 changed files with 65 additions and 20 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
.git

View File

@ -258,7 +258,8 @@ LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'), ]
# https://docs.djangoproject.com/en/1.10/howto/static-files/ # https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static") STATIC_ROOT = os.path.join(PROJECT_DIR, "data", "static")
STATIC_DIR = os.path.join(BASE_DIR, "static")
STATICFILES_DIRS = ( STATICFILES_DIRS = (

View File

@ -36,6 +36,6 @@ urlpatterns = [
if settings.DEBUG: if settings.DEBUG:
urlpatterns += [ urlpatterns += [
url(r'^docs/', schema_view, name="docs"), url(r'^docs/', schema_view, name="docs"),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ ] + static(settings.STATIC_URL, document_root=settings.STATIC_DIR) \
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -3,11 +3,13 @@
from collections import OrderedDict from collections import OrderedDict
import copy import copy
import logging import logging
import os import os
import uuid
from rest_framework import viewsets, serializers from rest_framework import viewsets, serializers
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
from django.core.cache import cache
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.utils import timezone from django.utils import timezone
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
@ -35,7 +37,7 @@ class TerminalViewSet(viewsets.ModelViewSet):
x_real_ip = request.META.get('X-Real-IP') x_real_ip = request.META.get('X-Real-IP')
remote_addr = x_real_ip or remote_ip remote_addr = x_real_ip or remote_ip
terminal = get_object_or_none(Terminal, name=name) terminal = get_object_or_none(Terminal, name=name, is_deleted=False)
if terminal: if terminal:
msg = 'Terminal name %s already used' % name msg = 'Terminal name %s already used' % name
return Response({'msg': msg}, status=409) return Response({'msg': msg}, status=409)
@ -46,12 +48,11 @@ class TerminalViewSet(viewsets.ModelViewSet):
if serializer.is_valid(): if serializer.is_valid():
terminal = serializer.save() terminal = serializer.save()
app_user, access_key = terminal.create_app_user()
data = OrderedDict() # App should use id, token get access key, if accepted
data['terminal'] = copy.deepcopy(serializer.data) token = uuid.uuid4().hex
data['user'] = app_user.to_json() cache.set(token, str(terminal.id), 3600)
data['access_key'] = {'id': access_key.id, data = {"id": str(terminal.id), "token": token, "msg": "Need accept"}
'secret': access_key.secret}
return Response(data, status=201) return Response(data, status=201)
else: else:
data = serializer.errors data = serializer.errors
@ -63,6 +64,36 @@ class TerminalViewSet(viewsets.ModelViewSet):
return super().get_permissions() return super().get_permissions()
class TerminalTokenApi(APIView):
permission_classes = (AllowAny,)
queryset = Terminal.objects.filter(is_deleted=False)
def get(self, request, *args, **kwargs):
try:
terminal = self.queryset.get(id=kwargs.get('terminal'))
except Terminal.DoesNotExist:
terminal = None
token = request.query_params.get("token")
if terminal is None:
return Response('May be reject by administrator', status=401)
if token is None or cache.get(token, "") != str(terminal.id):
return Response('Token is not valid', status=401)
if not terminal.is_accepted:
return Response("Terminal was not accepted yet", status=400)
if not terminal.user or not terminal.user.access_key.all():
return Response("No access key generate", status=401)
access_key = terminal.user.access_key.first()
data = OrderedDict()
data['access_key'] = {'id': access_key.id, 'secret': access_key.secret}
return Response(data, status=200)
class StatusViewSet(viewsets.ModelViewSet): class StatusViewSet(viewsets.ModelViewSet):
queryset = Status.objects.all() queryset = Status.objects.all()
serializer_class = StatusSerializer serializer_class = StatusSerializer

View File

@ -11,7 +11,7 @@ from .backends.command.models import AbstractSessionCommand
class Terminal(models.Model): class Terminal(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=32, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=32, verbose_name=_('Name'))
remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address')) remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address'))
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222) ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000) http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
@ -34,7 +34,8 @@ class Terminal(models.Model):
self.user.save() self.user.save()
def create_app_user(self): def create_app_user(self):
user, access_key = User.create_app_user(name=self.name, comment=self.comment) random = uuid.uuid4().hex[:6]
user, access_key = User.create_app_user(name="{}-{}".format(self.name, random), comment=self.comment)
self.user = user self.user = user
self.save() self.save()
return user, access_key return user, access_key
@ -42,6 +43,7 @@ class Terminal(models.Model):
def delete(self, using=None, keep_parents=False): def delete(self, using=None, keep_parents=False):
if self.user: if self.user:
self.user.delete() self.user.delete()
self.user = None
self.is_deleted = True self.is_deleted = True
self.save() self.save()
return return

View File

@ -14,8 +14,11 @@ class TerminalSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Terminal model = Terminal
fields = ['id', 'name', 'remote_addr', 'http_port', 'ssh_port', fields = [
'comment', 'is_accepted', 'session_online', 'is_alive'] 'id', 'name', 'remote_addr', 'http_port', 'ssh_port',
'comment', 'is_accepted', "is_active", 'session_online',
'is_alive'
]
@staticmethod @staticmethod
def get_session_online(obj): def get_session_online(obj):

View File

@ -89,7 +89,7 @@ function initTable() {
], ],
ajax_url: '{% url "api-terminal:terminal-list" %}', ajax_url: '{% url "api-terminal:terminal-list" %}',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"}, columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"},
{data: "session_online"}, {data: "is_accepted" }, {data: 'is_alive'}, {data: "id"}], {data: "session_online"}, {data: "is_active" }, {data: 'is_alive'}, {data: "id"}],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
jumpserver.initDataTable(options); jumpserver.initDataTable(options);

View File

@ -20,6 +20,7 @@ urlpatterns = [
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$', url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$',
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
name='session-replay'), name='session-replay'),
url(r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key')
] ]
urlpatterns += router.urls urlpatterns += router.urls

View File

@ -73,6 +73,7 @@ class TerminalAcceptView(AdminUserRequiredMixin, JSONResponseMixin, UpdateView):
def form_valid(self, form): def form_valid(self, form):
terminal = form.save() terminal = form.save()
terminal.create_app_user()
terminal.is_accepted = True terminal.is_accepted = True
terminal.is_active = True terminal.is_active = True
terminal.save() terminal.save()

View File

@ -28,13 +28,13 @@ class User(AbstractUser):
('App', 'Application') ('App', 'Application')
) )
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField(max_length=20, unique=True, verbose_name=_('Username')) username = models.CharField(max_length=128, unique=True, verbose_name=_('Username'))
name = models.CharField(max_length=20, verbose_name=_('Name')) name = models.CharField(max_length=128, verbose_name=_('Name'))
email = models.EmailField(max_length=30, unique=True, verbose_name=_('Email')) email = models.EmailField(max_length=128, unique=True, verbose_name=_('Email'))
groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group')) groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group'))
role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role')) role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role'))
avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar')) avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar'))
wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat')) wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat'))
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone')) phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP')) enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
secret_key_otp = models.CharField(max_length=16, blank=True) secret_key_otp = models.CharField(max_length=16, blank=True)
@ -212,7 +212,7 @@ class User(AbstractUser):
def create_app_user(cls, name, comment): def create_app_user(cls, name, comment):
from . import AccessKey from . import AccessKey
app = cls.objects.create( app = cls.objects.create(
username=name, name=name, email='%s@local.domain'.format(), username=name, name=name, email='{}@local.domain'.format(name),
is_active=False, role='App', enable_otp=False, comment=comment, is_active=False, role='App', enable_otp=False, comment=comment,
is_first_login=False, created_by='System' is_first_login=False, created_by='System'
) )

View File

@ -21,6 +21,11 @@ DEBUG = CONFIG.DEBUG
LOG_LEVEL = CONFIG.LOG_LEVEL LOG_LEVEL = CONFIG.LOG_LEVEL
WORKERS = 4 WORKERS = 4
try:
os.makedirs(os.path.join(BASE_DIR, "data", "static"))
os.makedirs(os.path.join(BASE_DIR, "data", "media"))
except:
pass
def start_gunicorn(): def start_gunicorn():
print("# Start Gunicorn WSGI HTTP Server") print("# Start Gunicorn WSGI HTTP Server")