Explorar el Código

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

Shellmiao hace 4 años
padre
commit
bc89d62d29
Se han modificado 8 ficheros con 154 adiciones y 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
      db.sqlite3

+ 12 - 0
account/admin.py

@@ -1,3 +1,15 @@
 from django.contrib import admin
 from django.contrib import admin
+from .models import Profile, Devices
+
 
 
 # Register your models here.
 # 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):
 class UserLoginForm(forms.Form):
     username = forms.CharField()
     username = forms.CharField()
     password = forms.CharField()
     password = forms.CharField()
+    token = forms.CharField()
 
 
 
 
 class UserRegisterForm(forms.ModelForm):
 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)
         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实例的时候自动调用
 # 信号接收函数,每当新建User实例的时候自动调用
 @receiver(post_save, sender=User)
 @receiver(post_save, sender=User)
 def create_user_profile(sender, instance, created, **kwargs):
 def create_user_profile(sender, instance, created, **kwargs):

+ 5 - 0
account/templates/login.html

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

+ 88 - 20
account/views.py

@@ -2,6 +2,15 @@ from django.shortcuts import render, redirect
 from .form import UserLoginForm, UserRegisterForm
 from .form import UserLoginForm, UserRegisterForm
 from django.contrib.auth import authenticate, login, logout
 from django.contrib.auth import authenticate, login, logout
 from django.http import HttpResponse
 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):
 def user_login(request):
@@ -10,22 +19,74 @@ def user_login(request):
         if user_login_form.is_valid():
         if user_login_form.is_valid():
             # 清洗出合法的数据
             # 清洗出合法的数据
             data = user_login_form.cleaned_data
             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:
             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:
         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:
     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):
 def user_logout(request):
@@ -37,15 +98,22 @@ def user_register(request):
     if request.method == 'POST':
     if request.method == 'POST':
         user_register_form = UserRegisterForm(data=request.POST)
         user_register_form = UserRegisterForm(data=request.POST)
         if user_register_form.is_valid():
         if user_register_form.is_valid():
+            # 新建一个user,但是不提交
             new_user = user_register_form.save(commit=False)
             new_user = user_register_form.save(commit=False)
+            # 设置密码
             new_user.set_password(user_register_form.cleaned_data['password'])
             new_user.set_password(user_register_form.cleaned_data['password'])
+            # 保存
             new_user.save()
             new_user.save()
-            return redirect("account:login")
+            response = {'result': 'reg successfully'}
+            return HttpResponse(json.dumps(response))
         else:
         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:
     else:
-        return HttpResponse('请使用POST或GET请求数据')
+        response = {'result', 'illegal method, please use post'}
+        return HttpResponse(json.dumps(response))

BIN
db.sqlite3