(身份验证和用户管理)
我们将通过实施用户管理和身份验证来启动 chatire,以便用户可以创建帐户并登录。
感谢 Django 优秀且充满活力的社区,大部分工作已经为我们完成。因此我们将使用一个名为djoser的第三方 django 库
让我们从pypi
pip install djangorestframework
pip install djoser
Djoser 是 Django 内置身份验证系统的 REST 实现。因此,它不是返回 html 的表单和视图,而是为我们提供了用于用户注册、令牌创建、用户管理等的 REST 端点。
配置djoser
我们将对 djoser 进行尽可能简单的设置。将以下内容包含在您的INSTALLED_APPS
INSTALLED_APPS = (
'django.contrib.auth',
...,
'rest_framework',
'rest_framework.authtoken',
'djoser',
)
将 djoser 的 url 添加到urls.py:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
...,
path('auth/', include('djoser.urls')),
path('auth/', include('djoser.urls.authtoken')),
]
包含rest_framework.authentication.TokenAuthenticationdjango Rest 框架的身份验证类:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
(...)
),
}
最后,运行数据库迁移python manage.py migrate将创建djsoer.
就是这样!身份验证端点现在可供使用。让我们创建一个新用户:
curl -X POST http://127.0.0.1:8000/auth/users/create/ --data 'username=danidee&password=mypassword'
{"email":"","username":"danidee","id":1}
瞧!我们有一个新用户。查看 djoser 文档以获取可用端点列表以及如何使用它们 http://djoser.readthedocs.io/en/latest/base_endpoints.htmlhttp :// djoser . 阅读文档。io / en / latest / base_端点。_ html
Vue.js
Vue 是一个用于构建响应式界面的 JavaScript 框架。尽管我是 React 的忠实粉丝(由于 React-native),但我仍然更喜欢使用 Vue 来开发 Web 应用程序。
原因之一是它的学习曲线平缓,它非常容易上手,并且与 React 不同,您不需要构建管道(使用 Webpack 和 co)来构建生产就绪的应用程序。您可以<script>像使用 一样包含外部标签JQuery。
它还有一个充满活力的社区,网上有很多插件和教程。
我们将使用它vue-cli来快速创建一个 Vue 应用程序(而不是<script>tag 方法)。ES6+这种方法使我们能够充分利用单文件 Vue 组件的全部功能。
vue-cli从 npm安装:
npm install -g vue-cli
让我们基于 webpack 模板构建一个新项目vue-cli
vue init webpack chatire-frontend
注意:确保选择“安装 vue-router”选项
这可能是喝杯咖啡或吃点快餐的最佳时机,因为这可能需要一些时间,具体取决于您的网络速度。我们尼日利亚的 ISP 真的很糟糕。花了10多分钟。
之后导航到新的 vue 应用程序并使用以下命令运行开发服务器:
npm run dev。
当你访问时你应该会看到这个localhost:8080

让我们稍微讨论一下文件夹结构:
.
├── build
│ ├── build.js
│ ├── check-versions.js
│ ├── logo.png
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── config
│ ├── dev.env.js
│ ├── index.js
│ ├── prod.env.js
│ └── test.env.js
├── index.html
├── node_modules
├── package.json
├── package-lock.json
├── README.md
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ ├── main.js
│ └── router
│ └── index.js
├── static
└── test
├── e2e
│ ├── custom-assertions
│ │ └── elementCount.js
│ ├── nightwatch.conf.js
│ ├── runner.js
│ └── specs
│ └── test.js
└── unit
├── jest.conf.js
├── setup.js
└── specs
└── HelloWorld.spec.js
- build:此目录包含用于运行 webpack 开发服务器或在准备部署到生产时捆绑应用程序的脚本。例如,
npm run dev该命令实际上运行:webpack-dev-server --inline --progress --config build/webpack.dev.conf.js该--inline选项将生成的静态文件注入到我们的index.html页面中。 - config:正如其名称所示,您应该存储用于开发、测试和生产的配置值
- src:这是我们编写大部分代码的地方,它包含应用程序不同方面的子文件夹。 我们的单个文件组件将放置在该文件夹中。那里已经有一个默认
HelloWorld.vue组件。 router文件夹中的文件index.js包含vue-router的配置 - static:静态文件(HTML、CSS 和 JavaScript)应存储在此文件夹中。
- test:最后, webpack 模板通过生成使用Nightwatch运行的端到端测试 (e2e)和使用Jest
vue-cli运行的单元测试,可以轻松测试我们的应用程序。 测试可以与npm run unit(对于单元测试)和npm run e2e端到端测试一起运行。
vue-cli还为我们设置了热重载,这确实改善了开发者的体验。编辑组件后点击“保存”后,更改会立即反映在浏览器中。
配置Vue路由器
在文件夹中创建两个组件components。一个用于主聊天屏幕Chat.vue,另一个用于用户身份验证和注册,我们将其称为UserAuth.vue
理想情况下,我们想要的是根据用户的登录状态有条件地显示组件。如果用户已通过身份验证,我们希望显示聊天组件,否则我们希望他们注册或登录,这意味着我们将显示该UserAuth组件。
https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-8618431079416074&output=html&h=200&slotname=8239403128&adk=2243974991&adf=1373591178&pi=t.ma~as.8239403128&w=867&fwrn=4&lmt=1616559018&rafmt=11&format=867×200&url=https%3A%2F%2Fdanidee10.github.io%2F2018%2F01%2F03%2Frealtime-django-2.html&wgl=1&uach=WyJXaW5kb3dzIiwiMTUuMC4wIiwieDg2IiwiIiwiMTE4LjAuNTk5My4xMjAiLG51bGwsMCxudWxsLCI2NCIsW1siQ2hyb21pdW0iLCIxMTguMC41OTkzLjEyMCJdLFsiR29vZ2xlIENocm9tZSIsIjExOC4wLjU5OTMuMTIwIl0sWyJOb3Q9QT9CcmFuZCIsIjk5LjAuMC4wIl1dLDBd&dt=1699282500698&bpp=1&bdt=234&idt=105&shv=r20231101&mjsv=m202311010101&ptt=9&saldr=aa&abxe=1&prev_fmts=0x0%2C922x280&nras=1&correlator=6473486370751&frm=20&pv=1&ga_vid=1624410613.1699282327&ga_sid=1699282501&ga_hid=1782970992&ga_fc=1&rplot=4&u_tz=480&u_his=3&u_h=720&u_w=1280&u_ah=672&u_aw=1280&u_cd=24&u_sd=1.5&dmc=8&adx=198&ady=5298&biw=1263&bih=595&scr_x=0&scr_y=2925&eid=44759875%2C44759926%2C44759837%2C31079307%2C31079404%2C44807048%2C44807334%2C44807454%2C44807461%2C31078301%2C31079356%2C31079382%2C31078663%2C31078665%2C31078668%2C31078670&oid=2&pvsid=2525487488543578&tmod=2054120635&uas=1&nvt=1&ref=https%3A%2F%2Fdanidee10.github.io%2F2018%2F01%2F01%2Frealtime-django-1.html&fc=1920&brdim=0%2C0%2C0%2C0%2C1280%2C0%2C1280%2C672%2C1280%2C595&vis=1&rsz=%7C%7CpEebr%7C&abl=CS&pfx=0&fu=128&bc=31&td=1&psd=W251bGwsbnVsbCxudWxsLDNd&nt=1&ifi=3&uci=a!3&btvi=1&fsb=1&xpc=bVHKrMma41&p=https%3A//danidee10.github.io&dtd=38186
我们可以通过创建一个实现全局导航来做到这一点。编辑路由器的index.js文件以包含以下内容
import Vue from 'vue'
import Router from 'vue-router'
import Chat from '@/components/Chat'
import UserAuth from '@/components/UserAuth'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/chats',
name: 'Chat',
component: Chat
},
{
path: '/auth',
name: 'UserAuth',
component: UserAuth
}
]
})
router.beforeEach((to, from, next) => {
if (sessionStorage.getItem('authToken') !== null || to.path === '/auth') {
next()
}
} else {
next('/auth')
}
})
export default router
beforeEach在导航到我们应用程序中的任何路线之前都会调用守卫。
如果令牌存储在中,sessionStorage我们允许通过调用继续导航next(),否则我们重定向到身份验证组件。
无论用户在我们的应用程序中导航到哪个路线,该函数都会检查用户是否具有身份验证令牌并适当地重定向它们。
登录/注册页面
我用 Bootstrap 4 选项卡构建了一个简单的登录/注册页面,内容如下UserAuth.vue:
<template>
<div class="container">
<h1 class="text-center">Welcome to Chatire!</h1>
<div id="auth-container" class="row">
<div class="col-sm-4 offset-sm-4">
<ul class="nav nav-tabs nav-justified" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="signup-tab" data-toggle="tab" href="#signup" role="tab" aria-controls="signup" aria-selected="true">Sign Up</a>
</li>
<li class="nav-item">
<a class="nav-link" id="signin-tab" data-toggle="tab" href="#signin" role="tab" aria-controls="signin" aria-selected="false">Sign In</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="signup" role="tabpanel" aria-labelledby="signin-tab">
<form @submit.prevent="signUp">
<div class="form-group">
<input v-model="email" type="email" class="form-control" id="email" placeholder="Email Address" required>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<input v-model="username" type="text" class="form-control" id="username" placeholder="Username" required>
</div>
<div class="form-group col-md-6">
<input v-model="password" type="password" class="form-control" id="password" placeholder="Password" required>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="toc" required>
<label class="form-check-label" for="gridCheck">
Accept terms and Conditions
</label>
</div>
</div>
<button type="submit" class="btn btn-block btn-primary">Sign up</button>
</form>
</div>
<div class="tab-pane fade" id="signin" role="tabpanel" aria-labelledby="signin-tab">
<form @submit.prevent="signIn">
<div class="form-group">
<input v-model="username" type="text" class="form-control" id="username" placeholder="Username" required>
</div>
<div class="form-group">
<input v-model="password" type="password" class="form-control" id="password" placeholder="Password" required>
</div>
<button type="submit" class="btn btn-block btn-primary">Sign in</button>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
const $ = window.jQuery // JQuery
export default {
data () {
return {
email: '', username: '', password: ''
}
}
}
</script>
<style scoped>
#auth-container {
margin-top: 50px;
}
.tab-content {
padding-top: 20px;
}
</style>
在上面的代码片段中,v-model用于所有输入字段上的双向数据绑定。这意味着在这些字段中输入的任何内容都可以在 JavaScript 端使用this.field_name.
我们还在两种表单上创建了事件侦听器,使用@submit.prevent它将侦听每个表单的表单提交事件并调用指定的方法。我们还没有实现这些方法。
由于我们正在使用Bootstrap,而不是jQuery从安装,我们定义了一个指向全局注册的npm变量。$window.jQuery
我们将使用jQuery的 ajax 方法与 django 服务器进行通信。如果您想将应用程序与jQuery. 它在Vue用户中很受欢迎。
不要忘记在主页中包含 bootstrap 的 CSS 和 JavaScript index.html。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous">
<style>
.nav-tabs .nav-item.show .nav-link, .nav-tabs .nav-link.active {
outline: none;
}
</style>
<title>chatire-frontend</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js" integrity="sha384-a5N7Y/aK3qNeh15eJKGWxsqtnX/wWdSZSKp+81YjTmS15nvnvxKHuzaWwXHDli+4" crossorigin="anonymous"></script>
</body>
</html>
该页面应如下所示:

相当不错啊?
让我们获取我们的身份验证令牌
我们想要注册用户,然后将他们重定向到聊天路由。
为了实现这一点,我们必须实现之前指定的signUp和方法:signIn
methods: {
signUp () {
$.post('http://localhost:8000/auth/users/create/', this.$data, (data) => {
alert("Your account has been created. You will be signed in automatically")
this.signIn()
})
.fail((response) => {
alert(response.responseText)
})
},
signIn () {
const credentials = {username: this.username, password: this.password}
$.post('http://localhost:8000/auth/token/create/', credentials, (data) => {
sessionStorage.setItem('authToken', data.auth_token)
sessionStorage.setItem('username', this.username)
this.$router.push('/chats')
})
.fail((response) => {
alert(response.responseText)
})
}
}
现在尝试提交表单。哎呀!它失败了:
跨源请求被阻止:同源策略不允许读取 http://localhost:8000/auth/users/create 处的远程资源。(原因:CORS 标头“Access-Control-Allow-Origin”丢失)。http :// localhost : 8000 / auth / users / create。(原因:CORS 标头“Access-Control-Allow-Origin”丢失)。
跨域资源共享
引用 mozilla 开发者网站:
跨源资源共享 (CORS) 是一种机制,它使用附加的 HTTP 标头来让用户代理获得从与当前使用的站点不同的源(域)上的服务器访问所选资源的权限。当用户代理从与当前文档来源不同的域、协议或端口请求资源时,它会发出跨源 HTTP 请求。
本质上是一种颠覆同源政策的机制。同源策略可以防止不同域上的网站XmlHttpRequest向另一个网站/Web 服务创建 (Ajax)。您可以使用 CORS 稍微削弱安全机制,并告诉 Web 服务器允许来自特定域的 Ajax 请求是安全的。
在我们的例子中,即使两个网络服务器都在本地主机上运行,由于它们位于不同的端口(8080 和 8000),因此它们被视为不同的域。
http对于与方案 (或)匹配的域https,主机名 ( localhost) 和端口必须匹配。
那么我们如何在 django 应用程序中启用 CORS?我们可以安装第三方应用程序来执行此操作,称为django-cors-headers.
pip install django-cors-headers
将其添加到您的INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Custom Apps 'rest_framework',
'rest_framework.authtoken',
'corsheaders',
'djoser'
]
包括中间件,(确保它位于之前django.middleware.common.CommonMiddleware)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
终于定了CORS_ORIGIN_ALLOW_ALL = True
请注意,这将为所有域启用 CORS。这对于开发来说很好,但是当您在生产中时,您只想允许某些域,这可以通过以下方式控制:
CORS_ORIGIN_WHITELIST
阅读 django-cors-header文档以了解其他选项。
完成此操作后,您应该能够创建帐户并立即登录。
在幕后,django-cors-headers使用中间件向每个请求添加适当的标头,告诉 Django 该请求是安全的并且应该被允许。
登出
因为我们用来sessionStorage存储身份验证令牌,所以我们可以通过打开新的浏览器选项卡来启动新会话。
要在浏览器重新启动/新选项卡之间实际保留令牌,您可以切换到localStorage. 它与 具有相同的 api,sessionStorage因此您只需更改session为local.
然后,您可以创建一个函数,通过调用从您决定保留的存储中删除令牌removeItem。这就是我们要做的localStorage。
localStorage.removeItem('authToken')
回顾
这就是这部分的全部内容,我们的目标是构建一个简单的用户管理和身份验证系统。我们首先安装 djoser,它是一个优秀的第三方 django 应用程序,提供REST身份验证端点。
我们还了解了如何使用jQuery的 ajax 方法从 Vue 调用这些端点。
在通往胜利的路上,我们被拦住了Same origin policy,我们简短地谈论了它为什么存在。最终我们学会了如何使用CORSthrough允许从 Vue 应用程序到 django 后端的 Ajax 请求django-cors-headers。
在下一部分中,我们将为聊天应用程序构建 django 模型和 API。