Explorar o código

完成了登录注册的接口、json数据的传送、接口约定文档、token持久登录机制与过期机制

Shellmiao %!s(int64=4) %!d(string=hai) anos
pai
achega
bc89d62d29
Modificáronse 8 ficheiros con 154 adicións e 20 borrados
  1. 12 0
      account/admin.py
  2. 1 0
      account/form.py
  3. 10 0
      account/interface.md
  4. 26 0
      account/migrations/0002_devices.py
  5. 12 0
      account/models.py
  6. 5 0
      account/templates/login.html
  7. 88 20
      account/views.py
  8. BIN=BIN
      db.sqlite3

+ 12 - 0
account/admin.py

@@ -1,3 +1,15 @@
 from django.contrib import admin
+from .models import Profile, Devices
+
 
 # Register your models here.
+class ProfileAdmin(admin.ModelAdmin):
+    list_display = ["user", "phone", "bio"]
+
+
+class DevicesAdmin(admin.ModelAdmin):
+    list_display = ["user", "last_login_time", "device_uid", "token"]
+
+
+admin.site.register(Profile, ProfileAdmin)
+admin.site.register(Devices, DevicesAdmin)

+ 1 - 0
account/form.py

@@ -6,6 +6,7 @@ from .models import Profile
 class UserLoginForm(forms.Form):
     username = forms.CharField()
     password = forms.CharField()
+    token = forms.CharField()
 
 
 class UserRegisterForm(forms.ModelForm):

+ 10 - 0
account/interface.md

@@ -0,0 +1,10 @@
+# 登录
+## 返回值接口约定
+result:['token time out',
+    'detected new device',
+    'wrong account or password',
+    'illegal input',
+    'illegal method, please use post',
+    'login successfully',
+    'reg successfully',
+]

+ 26 - 0
account/migrations/0002_devices.py

@@ -0,0 +1,26 @@
+# Generated by Django 3.2.5 on 2021-07-08 07:38
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('account', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Devices',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('last_login_time', models.DateField(auto_now=True)),
+                ('device_uid', models.CharField(max_length=100)),
+                ('token', models.CharField(default='233', max_length=100)),
+                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='devices', to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]

+ 12 - 0
account/models.py

@@ -19,6 +19,18 @@ class Profile(models.Model):
         return 'user {}'.format(self.user.username)
 
 
+# 设备表
+class Devices(models.Model):
+    # 对应django自带的User
+    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='devices')
+    # 设备登录时间
+    last_login_time = models.DateField(auto_now=True)
+    # 设备码
+    device_uid = models.CharField(max_length=100, blank=False)
+    # 登录凭证
+    token = models.CharField(max_length=100, default='233', blank=False)
+
+
 # 信号接收函数,每当新建User实例的时候自动调用
 @receiver(post_save, sender=User)
 def create_user_profile(sender, instance, created, **kwargs):

+ 5 - 0
account/templates/login.html

@@ -13,6 +13,11 @@
                 <label for="password">密码</label>
                 <input type="password" id="password" name="password">
             </div>
+            <!-- new_token -->
+            <div>
+                <label for="token">新token</label>
+                <input type="text" id="token" name="token">
+            </div>
             <!-- 提交按钮 -->
             <button type="submit">提交</button>
         </form>

+ 88 - 20
account/views.py

@@ -2,6 +2,15 @@ from django.shortcuts import render, redirect
 from .form import UserLoginForm, UserRegisterForm
 from django.contrib.auth import authenticate, login, logout
 from django.http import HttpResponse
+from .models import Profile, Devices
+import random
+import datetime
+import json
+
+"""
+在此处修改token过期时间,30代表30天过期
+"""
+expiration_date = 30
 
 
 def user_login(request):
@@ -10,22 +19,74 @@ def user_login(request):
         if user_login_form.is_valid():
             # 清洗出合法的数据
             data = user_login_form.cleaned_data
-            # 检测账号密码是否匹配数据库中的一个用户
-            # 如果均匹配,则返回此User对象
-            user = authenticate(username=data['username'], password=data['password'])
-            if user:
-                login(request, user)
-                return redirect("chat:index")
+            # 检测是否有登录凭证
+            if data['token'] != 'token':
+                try:
+                    device = Devices.objects.filter(token__exact=data['token']).get()
+                    sub_time = (device.last_login_time - datetime.date).total_seconds() / (3600 * 24)
+                    # 检查token是否过期
+
+                    if sub_time < expiration_date:
+                        # 更新此user此设备的token
+                        # token由设备uid、用户名、当前时间hash得来
+                        device.token = hash(
+                            device.device_uid + device.user.username + datetime.datetime.now().strftime("%Y%m%d%H%M%S"))
+                        device.save()
+                        # 登录
+                        user = device.user
+                        login(request, user)
+                        response = {'result': 'login successfully'}
+                        return HttpResponse(json.dumps(response))
+                        # return redirect("chat:index")
+                    else:
+                        response = {'result': 'token time out'}
+                        return HttpResponse(json.dumps(response))
+                # 已过期的token并且已经被删除
+                except Devices.DoesNotExist:
+                    response = {'result': 'detected new device'}
+                    return HttpResponse(json.dumps(response))
             else:
-                return HttpResponse("账号或密码输入不正确,请重新输入")
+                # 检测账号密码是否匹配数据库中的一个用户
+                # 如果均匹配,则返回此User对象
+                user = authenticate(username=data['username'], password=data['password'])
+                if user:
+                    # 新建一个该user的设备
+                    device = Devices()
+                    device.user = user
+                    device.device_uid = generate_random_str(10)
+                    device.token = hash(
+                        device.device_uid + device.user.username + datetime.datetime.now().strftime("%Y%m%d%H%M%S"))
+                    device.save()
+                    login(request, user)
+                    response = {'result': 'login successfully'}
+                    return HttpResponse(json.dumps(response))
+                else:
+                    response = {'result': 'wrong account or password'}
+                    return HttpResponse(json.dumps(response))
         else:
-            return HttpResponse("输入不合法,请重新输入")
-    elif request.method == 'GET':
-        user_login_form = UserLoginForm()
-        context = {'form': user_login_form}
-        return render(request, 'login.html', context)
+            response = {'result', 'illegal input'}
+            return HttpResponse(json.dumps(response))
+    # 用于测试,登录界面
+    # elif request.method == 'GET':
+    #     user_login_form = UserLoginForm()
+    #     context = {'form': user_login_form}
+    #     return render(request, 'login.html', context)
     else:
-        return HttpResponse("请使用GET或者POST请求数据")
+        # 请求方法错误,请使用POST
+        response = {'result', 'illegal method, please use post'}
+        return HttpResponse(json.dumps(response))
+
+
+def generate_random_str(random_length=16):
+    """
+    生成一个指定长度的随机字符串
+    """
+    random_str = ''
+    base_str = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
+    length = len(base_str) - 1
+    for i in range(random_length):
+        random_str += base_str[random.randint(0, length)]
+    return random_str
 
 
 def user_logout(request):
@@ -37,15 +98,22 @@ def user_register(request):
     if request.method == 'POST':
         user_register_form = UserRegisterForm(data=request.POST)
         if user_register_form.is_valid():
+            # 新建一个user,但是不提交
             new_user = user_register_form.save(commit=False)
+            # 设置密码
             new_user.set_password(user_register_form.cleaned_data['password'])
+            # 保存
             new_user.save()
-            return redirect("account:login")
+            response = {'result': 'reg successfully'}
+            return HttpResponse(json.dumps(response))
         else:
-            return HttpResponse('注册表单输入有误,请重新输入')
-    elif request.method == 'GET':
-        user_register_form = UserRegisterForm()
-        context = {'form': user_register_form}
-        return render(request, 'register.html', context)
+            response = {'result', 'illegal input'}
+            return HttpResponse(json.dumps(response))
+    # 用于测试
+    # elif request.method == 'GET':
+    #     user_register_form = UserRegisterForm()
+    #     context = {'form': user_register_form}
+    #     return render(request, 'register.html', context)
     else:
-        return HttpResponse('请使用POST或GET请求数据')
+        response = {'result', 'illegal method, please use post'}
+        return HttpResponse(json.dumps(response))

BIN=BIN
db.sqlite3