万字长文——管理员登录/注册界面后端(Django+Vue3)

🌟 如果这篇文章触动了你的心弦,请不要吝啬你的支持!

亲爱的读者,

感谢你花时间阅读这篇分享。希望这里的每一个字都能为你带来启发或是让你会心一笑。如果你觉得这篇文章有价值,或者它解决了你一直以来的一个疑问,请给个赞吧 —— 这不仅是对我学习效果的认可,更是激励我继续前行的动力!

而且,如果你不想错过未来更多有趣的内容,记得点击关注哦!这样,每当有新文章发布时,你就能第一时间收到通知啦。让我们一起在这个充满无限可能的知识海洋中遨游,探索未知的世界吧!

最后,别忘了留下你的想法或问题在评论区。无论是赞美、建议还是疑问,我都非常期待听到你的声音。也许,正是你的那条评论,将开启一段全新的讨论旅程呢!

🌟 点赞、关注、留言 —— 三连走起,让我们共同成长,一起变得更优秀!

再次感谢每一位可爱的你,愿你在追求梦想的路上一帆风顺!

1、登录界面前端开发:

  1. 首先先写出两个视图(登录和注册界面)代码:

    views/Login.vue
    <template>
      <div class="login">
        <h2>管理员登录</h2>
        <form @submit.prevent="handleLogin">
          <input v-model="username" placeholder="用户名" required />
          <input v-model="password" type="password" placeholder="密码" required />
          <button type="submit">登录</button>
          <p v-if="error" class="error">{{ error }}</p>
        </form>
      </div>
    </template>
    ​
    <script setup>
    import { ref } from 'vue'
    import { useRouter } from 'vue-router'
    import { adminLogin } from '@/api/auth'
    ​
    const username = ref('')
    const password = ref('')
    const error = ref('')
    const router = useRouter()
    ​
    const handleLogin = async () => {
      try {
        const res = await adminLogin({ username: username.value, password: password.value })
        if (res.data.status === 'success') {
          localStorage.setItem('admin_token', res.data.token)
          router.push('/')
        } else {
          error.value = res.data.message || '登录失败'
        }
      } catch (e) {
        error.value = '请求错误: ' + e.message
      }
    }
    </script>
    ​
    <style scoped>
    .login {
      max-width: 360px;
      margin: auto;
      padding: 20px;
      text-align: center;
    }
    .error {
      color: red;
    }
    </style>
    ​
    views/register.vue
    <template>
      <div class="register-container">
        <h2>管理员注册</h2>
    ​
        <div class="form-group">
          <label>邮箱:</label>
          <input v-model="form.email" type="email" required />
        </div>
    ​
        <div class="form-group">
          <label>电话:</label>
          <input v-model="form.phone" type="tel" required />
        </div>
    ​
        <div class="form-group">
          <label>昵称:</label>
          <input v-model="form.nickname" type="text" required />
        </div>
    ​
        <div class="form-group">
          <label>密码:</label>
          <input v-model="form.password" type="password" required />
        </div>
    ​
        <div class="form-group">
          <label>确认密码:</label>
          <input v-model="form.confirmPassword" type="password" required />
        </div>
    ​
        <div class="error" v-if="error">{{ error }}</div>
        <div class="success" v-if="success">{{ success }}</div>
    ​
        <button @click="handleRegister">注册</button>
        <button @click="login">登录</button>
      </div>
    </template>
    ​
    <script setup>
    import { ref } from 'vue'
    import axios from '@/api/axios'
    import { useRouter } from 'vue-router'
    ​
    const form = ref({
      email: '',
      phone: '',
      nickname: '',
      password: '',
      confirmPassword: '',
    })
    ​
    const error = ref(null)
    const success = ref(null)
    const router = useRouter()
    ​
    const handleRegister = async () => {
      error.value = null
      success.value = null
    ​
      if (form.value.password.length < 6) {
        error.value = '密码长度至少为6位'
        return
      }
    ​
      if (form.value.password !== form.value.confirmPassword) {
        error.value = '两次密码不一致'
        return
      }
    ​
      try {
        const res = await axios.post('admin/register/', form.value)
        if (res.data.status === 'success') {
          success.value = '注册成功,正在登录...'
          // 保存 token
          localStorage.setItem('admin_token', res.data.token.access)
          localStorage.setItem('admin_user', JSON.stringify(res.data.user))
          setTimeout(() => router.push('/'), 1000)
        } else {
          error.value = res.data.message || '注册失败'
        }
      } catch (err) {
        error.value = '请求失败: ' + err.message
      }
    }
    ​
    const login = () => {
      router.push('/admin/login')
    }
    </script>
    ​
    <style scoped>
    .register-container {
      max-width: 400px;
      margin: auto;
      padding: 24px;
      font-family: Arial;
    }
    .form-group {
      margin-bottom: 10px;
    }
    .error {
      color: red;
    }
    .success {
      color: green;
    }
    button {
      padding: 8px 16px;
    }
    </style>
    ​
  2. 接着在router/index.js中添加路由路径:

    import Admin_Login from '../views/Admin_Login.vue'
    import AdminRegister from '../views/AdminRegister.vue'
    ​
    { path: '/admin/register', component: AdminRegister },
    { path: '/admin/login', component: Admin_Login },

    并添加一个路由守卫:

    // 路由守卫:检查登录状态
    router.beforeEach((to, from, next) => {
      const isAuthenticated = !!localStorage.getItem('admin_token')
      if (to.meta.requiresAuth && !isAuthenticated) {
        next('/admin/login')
      } else {
        next()
      }
    })

  3. 在api目录下创建一个新的接口文件→auth.js:

    该文件作用:写有关管理员的接口代码:

    import request from './axios'  // 正确引入你配置的 axios 实例
    ​
    export const adminLogin = (payload) => {
      return request.post('admin/login/', payload)
    }
    ​
    export const adminRegister = (payload) => {
      return request.post('admin/register/', payload)
    }
    ​
  4. 最后创建一个主页视图(Home.vue):

    <template>
      <div class="home">
        <h1>后台首页</h1>
        <button @click="goToSensorView" class="btn-primary">📊 查看传感器数据</button>
        <button @click="goTodesign_layoutView" class="btn-layout">📊 进行页面布局</button>
        <button @click="logout">退出登录</button>
      </div>
    </template>
    ​
    <script setup>
    import { useRouter } from 'vue-router'
    ​
    const router = useRouter()
    ​
    const logout = () => {
      localStorage.removeItem('admin_token')
      router.push('/admin/login')
    }
    ​
    const goToSensorView = () => {
      router.push('/sensor-view')
    }
    ​
    const goTodesign_layoutView = () => {
        router.push('/Design_layout-view')
    }
    </script>
    ​
    <style scoped>
    .btn-primary {
      background-color: #42b983;
      color: white;
      padding: 10px 16px;
      border: none;
      border-radius: 4px;
      margin-right: 10px;
      cursor: pointer;
    }
    .btn-layout{
      background-color: #42b983;
      color: white;
      padding: 10px 16px;
      border: none;
      border-radius: 4px;
      margin-right: 10px;
      cursor: pointer;
    }
    </style>
    ​
  5. 效果图:

    点击相应的按钮就会跳转相应的界面

2、管理员登录/注册界面后端:

  1. 安装必要的依赖项:

    pip install djangorestframework djangorestframework-simplejwt
  2. settings.py 中配置 JWT

    INSTALLED_APPS = [
           ...
           'rest_framework',
           'rest_framework_simplejwt',
           'corsheaders',  # 若使用前后端分离
       ]
    ​
       MIDDLEWARE = [
           'corsheaders.middleware.CorsMiddleware',  # 若使用前后端分离
           ...
       ]
    ​
       REST_FRAMEWORK = {
           'DEFAULT_AUTHENTICATION_CLASSES': (
               'rest_framework_simplejwt.authentication.JWTAuthentication',
           )
       }
    ​
       允许前端跨域访问
    ​
       CORS_ALLOW_ALL_ORIGINS = True
    ​
    ​
  3. 创建管理员登录视图(view.py中):

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework_simplejwt.tokens import RefreshToken
    from django.contrib.auth import authenticate
    ​
    class AdminLoginView(APIView):
        def post(self, request):
            username = request.data.get('username')
            password = request.data.get('password')
        user = authenticate(username=username, password=password)
        if user and user.is_staff:  # 限定为管理员登录
            refresh = RefreshToken.for_user(user)
            return Response({
                'status': 'success',
                'token': {
                    'refresh': str(refresh),
                    'access': str(refresh.access_token),
                },
                'user': {
                    'username': user.username,
                }
            })
        return Response({'status': 'error', 'message': '用户名或密码错误'}, status=401)
        
    @api_view(['POST'])
    def admin_register(request):
        data = request.data
        email = data.get('email')
        phone = data.get('phone')
        nickname = data.get('nickname')
        password = data.get('password')
        confirm_password = data.get('confirmPassword')
    ​
        # 基本校验
        if not all([email, phone, nickname, password, confirm_password]):
            return Response({"status": "error", "message": "所有字段都是必填的"}, status=400)
    ​
        if password != confirm_password:
            return Response({"status": "error", "message": "两次密码不一致"}, status=400)
    ​
        if len(password) < 6:
            return Response({"status": "error", "message": "密码长度必须不少于6位"}, status=400)
    ​
        if User.objects.filter(username=nickname).exists():
            return Response({"status": "error", "message": "该昵称已被注册"}, status=400)
    ​
        if User.objects.filter(email=email).exists():
            return Response({"status": "error", "message": "该邮箱已被注册"}, status=400)
    ​
        # 创建用户
        user = User.objects.create(
            username=nickname,
            email=email,
            password=make_password(password),
            first_name=phone
        )
    ​
        # 自动登录,生成 JWT token
        refresh = RefreshToken.for_user(user)
        return Response({
            "status": "success",
            "message": "注册成功",
            "token": {
                "refresh": str(refresh),
                "access": str(refresh.access_token)
            },
            "user": {
                "nickname": user.username,
                "email": user.email,
                "phone": user.first_name
            }
        })
  4. 注册路由(url.py中):

    from django.urls import path
    from .views import AdminLoginView
    ​
    urlpatterns = [
        path('api/admin/login/', views.AdminLoginView.as_view(), name='admin_login'),
        path('api/admin/register/', views.admin_register,name="admin_register")
    ]

3、涉及知识点的简单讲解

3.1.Vue 3 + Composition API(组合式 API)

知识点:<script setup> 语法糖

  • Vue 3 引入了 setup 语法糖,简化组件逻辑编写。
  • 不需要写 export default {},直接声明变量和方法即可。

示例:

<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>

3.2.Axios 请求封装与拦截器

知识点:创建 Axios 实例并添加请求拦截器

  • 使用 axios.create() 创建自定义实例,便于统一管理基础路径和拦截逻辑。
  • 请求拦截器可用于自动携带 Token。

示例:

// api/axios.js
import axios from 'axios'

const instance = axios.create({
  baseURL: 'http://127.0.0.1:8000/api',
})

instance.interceptors.request.use(config => {
  const token = localStorage.getItem('admin_token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

export default instance

3.3.JWT 认证机制(JSON Web Token)

知识点:Django REST Framework Simple JWT

  • 使用 djangorestframework-simplejwt 实现基于 JWT 的认证。
  • 登录成功后返回 access 和 refresh token。

示例:

from rest_framework_simplejwt.tokens import RefreshToken

def get_tokens_for_user(user):
    refresh = RefreshToken.for_user(user)
    return {
        'refresh': str(refresh),
        'access': str(refresh.access_token),
    }

3.4.Vue Router 路由守卫

知识点:使用 beforeEach 拦截路由跳转,验证用户是否登录

  • 可用于实现登录权限控制,未登录用户无法访问受保护页面。

示例:

router.beforeEach((to, from, next) => {
  const isAuthenticated = !!localStorage.getItem('admin_token')
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/admin/login')
  } else {
    next()
  }
})

3.5.跨域问题处理(CORS)

知识点:配置 Django 后端允许跨域请求

  • 使用 django-cors-headers 插件解决前后端分离时的跨域限制。

安装:

pip install django-cors-headers

配置 settings.py:

INSTALLED_APPS = [
    ...
    'corsheaders',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

CORS_ALLOW_ALL_ORIGINS = True

3.6.表单验证与状态提示

知识点:前端手动进行表单字段校验并显示错误信息

  • 在提交前对密码长度、一致性等做判断,并通过响应式变量控制提示内容。

示例:

if (form.value.password.length < 6) {
  error.value = '密码长度至少为6位'
  return
}

3.7.LocalStorage 存储 Token 与用户信息

知识点:浏览器本地存储用户身份凭证

  • 登录成功后将 token 存入 localStorage,用于后续请求鉴权。

示例:

localStorage.setItem('admin_token', res.data.token.access)
localStorage.setItem('admin_user', JSON.stringify(res.data.user))

3.8.Django 用户模型与密码加密

知识点:使用内置 User 模型创建管理员用户,并用 make_password 加密密码

  • 避免明文保存密码,增强安全性。
from django.contrib.auth.hashers import make_password
user = User.objects.create(
    username=nickname,
    email=email,
    password=make_password(password),
)

3.9.DRF 视图类型选择:函数视图 vs 类视图

知识点:灵活使用 @api_view 和类视图开发接口

  • 函数视图适合简单逻辑。
  • 类视图更适合复杂业务和结构化开发。

函数视图示例:

@api_view(['POST'])
def admin_register(request):
    ...

类视图示例:

class AdminLoginView(APIView):
    def post(self, request):
        ...

3.10.权限控制装饰器 @permission_classes([AllowAny])

知识点:确保注册接口不需要认证即可访问

  • 默认 DRF 接口会要求认证,必须显式设置为允许匿名访问。

示例:

from rest_framework.decorators import permission_classes
from rest_framework.permissions import AllowAny

@api_view(['POST'])
@permission_classes([AllowAny])
def admin_register(request):
    ...

3.11.路由配置(urls.py)

知识点:将视图映射到具体的 URL 路径

  • 使用 path() 方法绑定视图函数或类视图。

示例:

from django.urls import path
from .views import AdminLoginView, admin_register

urlpatterns = [
    path('api/admin/login/', AdminLoginView.as_view(), name='admin_login'),
    path('api/admin/register/', admin_register, name='admin_register'),
]

 3.12.后端导入项有关拓展

1. from django.shortcuts import render

  • 用途render 函数用于将模板文件与数据结合后返回给客户端。它通常用于生成 HTML 页面响应。

  • 示例:在视图函数中,你可以使用 return render(request, 'template_name.html', context) 来渲染一个HTML页面。

2. import socket

  • 用途socket 库提供了一个底层的网络接口,可以用来创建TCP或UDP服务器和客户端。在这个上下文中,它可能被用于与另一个服务(如传感器数据服务)进行通信。

  • 示例:在你的代码中,它被用来通过TCP连接获取传感器的数据。

3. from django.http import JsonResponse

  • 用途JsonResponse 是 Django 提供的一个方便的方法,用于返回 JSON 编码的 HTTP 响应。特别适用于 API 开发时需要返回 JSON 数据的情况。

  • 示例return JsonResponse({"status": "success", "data": parsed_data}) 返回 JSON 格式的成功响应。

4. import json

  • 用途:尽管 Django 的 JsonResponse 可以自动处理大部分 JSON 操作,但有时你仍需手动解析或生成 JSON 数据。json 模块提供了更灵活的控制。

  • 示例parsed_data = json.loads(received_data) 将接收到的字符串转换为 Python 字典。

5. from rest_framework.views import APIView

  • 用途APIView 类是 Django REST framework (DRF) 中的基本类之一,用于构建RESTful API。它允许你定义基于类的方法来处理不同的HTTP请求类型(GET, POST等)。

  • 示例:定义一个类继承自 APIView 并实现 post() 方法来处理POST请求。

6. from rest_framework.response import Response

  • 用途Response 对象由 DRF 提供,支持内容协商(content negotiation),这意味着它可以自动根据客户端的要求返回适当格式的数据(比如JSON、XML等)。

  • 示例return Response({'status': 'error', 'message': '用户名或密码错误'}, status=401) 返回错误信息。

7. from rest_framework_simplejwt.tokens import RefreshToken

  • 用途RefreshToken 是 djangorestframework-simplejwt 包的一部分,用于生成JWT令牌。这包括刷新令牌(refresh token)和访问令牌(access token),前者可用于获取新的访问令牌。

  • 示例refresh = RefreshToken.for_user(user) 创建一个新的刷新令牌。

8. from django.contrib.auth import authenticate

  • 用途authenticate 函数用于验证用户凭据(如用户名和密码)。这是Django内置的身份验证系统的一部分。

  • 示例user = authenticate(username=username, password=password) 验证用户是否有效。

9. from rest_framework.decorators import api_view

  • 用途@api_view 装饰器允许你轻松地将普通的函数视图转换成DRF兼容的视图。它可以指定该视图接受哪些HTTP方法。

  • 示例@api_view(['POST']) 表明该视图仅处理POST请求。

10. from django.contrib.auth.models import User

  • 用途User 是Django默认的用户模型,用于存储应用中的用户信息。

  • 示例user = User.objects.create(...) 创建一个新的用户实例。

11. from django.contrib.auth.hashers import make_password

  • 用途make_password 函数用于对用户密码进行哈希处理,确保密码不会以明文形式保存到数据库中。

  • 示例password=make_password(password) 在创建新用户时对密码进行加密。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值