nuxt.js 全局 js
In this tutorial, you’ll implement authentication in a Nuxt.js app using the Auth
module. For the purpose of this tutorial we’ll be using JWT
for authentication.
在本教程中,您将使用Auth
模块在Nuxt.js应用中实现身份Auth
。 就本教程而言,我们将使用JWT
进行身份验证。
Below is a quick demo of what we’ll be building in this tutorial.
以下是我们将在本教程中构建的快速演示。
To save ourselves some time, we’ll clone an API, which you can do with the following command:
为了节省时间,我们将克隆一个API,您可以使用以下命令进行操作:
Then we install the API dependencies:
然后,我们安装API依赖项:
Next, rename .env.example
to .env
and generate an APP_KEY
:
接下来,将.env.example
重命名为.env
并生成一个APP_KEY
:
With the adonis CLI:
使用adonis CLI:
Without the adonis CLI:
没有adonis CLI:
Once that’s done, let’s run the migrations:
完成后,让我们运行迁移:
With the adonis CLI:
使用adonis CLI:
Without the adonis CLI:
没有adonis CLI:
Before we move on to building the Nuxt.js app, let’s quickly go over the API. The API is built using AdonisJs and it uses JWT (JSON Web Tokens) for authentication. It also uses SQLite.
在继续构建Nuxt.js应用之前,让我们快速浏览一下API。 该API使用AdonisJs构建 ,并且使用JWT(JSON Web令牌)进行身份验证。 它还使用SQLite。
The API has three endpoints:
该API具有三个端点:
/register
: endpoint for users registration.
/register
:用户注册的端点。
/login
: endpoint for authenticating users.
/login
:用于验证用户的端点。
/me
: endpoint for getting details for the currently authenticated user and it is protected by an auth
middleware, which means a user must be authenticated to access the endpoint.
/me
:端点,用于获取当前已认证用户的详细信息,并且受auth
中间件保护,这意味着必须对用户进行认证才能访问该端点。
The API also already has CORS enabled.
该API也已经启用了CORS。
Now, we can start the API:
现在,我们可以启动API:
We can access the API on http://127.0.0.1:3333/api
. We’ll leave it running.
我们可以通过http://127.0.0.1:3333/api
访问API。 我们将继续运行。
Note: Though I’ll be using an API built with AdonisJs for the purpose of this tutorial, you are free to use whatever framework that work best for you.
注意:尽管本教程将使用AdonisJs构建的API,但您可以自由使用最适合您的框架。
For this, we’ll make use of the Vue CLI, so you need to first install the Vue CLI in case you don’t have it installed already:
为此,我们将使用Vue CLI,因此,如果尚未安装Vue CLI,则需要先安装它:
Then we can create a Nuxt.js app:
然后,我们可以创建一个Nuxt.js应用程序:
Next, we need to install the dependencies:
接下来,我们需要安装依赖项:
We can launch the app:
我们可以启动该应用程序:
The app should be running on http://localhost:3000
.
该应用程序应在http://localhost:3000
。
Now, let’s install the Nuxt.js modules that we’ll be needing for our app. We’ll be using the Nuxt Auth module and the Nuxt Axios module, since the auth
module makes use of Axios internally:
现在,让我们安装应用程序所需的Nuxt.js模块。 我们将使用Nuxt Auth模块和Nuxt Axios模块 ,因为auth
模块在内部使用Axios:
Once that’s done, add the code below to nuxt.config.js
:
完成后,将以下代码添加到nuxt.config.js
:
modules: [
'@nuxtjs/axios',
'@nuxtjs/auth'
],
Next, we need to set up the modules. Paste the code below into nuxt.config.js
接下来,我们需要设置模块。 将以下代码粘贴到nuxt.config.js
axios: {
baseURL: 'http://127.0.0.1:3333/api'
},
auth: {
strategies: {
local: {
endpoints: {
login: { url: 'login', method: 'post', propertyName: 'data.token' },
user: { url: 'me', method: 'get', propertyName: 'data' },
logout: false
}
}
}
}
Here, we set the base URL (which is that of our API from earlier on) that Axios will use when making requests. Then we define the authentication endpoints for the local
strategy corresponding to those on our API. On successful authentication, the token will be available in the response as a token
object inside a data
object, hence why we set propertyName
to data.token
. Similarly, the response from the /me
endpoint will be inside a data
object. Lastly, we set logout
to false
since our API doesn’t have an endpoint for logout. We’ll just remove the token from localstorage when a user logs out.
在这里,我们设置了Axios在发出请求时将使用的基本URL(这是我们以前的API的基本URL)。 然后,我们为local
策略定义与API上相应的身份验证终结点。 成功认证后,令牌将作为data
对象内的token
对象在响应中可用,因此为什么我们将propertyName
设置为data.token
。 同样, /me
端点的响应将在data
对象内部。 最后,由于我们的API没有用于注销的端点,因此我们将logout
设置为false
。 当用户注销时,我们将从本地存储中删除令牌。
To style our app, we’ll be making use of Bulma. Open nuxt.config.js
and paste the code below within the link
object that is inside the head
object:
要设计我们的应用程序样式,我们将使用Bulma 。 打开nuxt.config.js
并将以下代码粘贴到head
对象内部的link
对象内:
{
rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css'
}
Now, let’s create the Navbar component. Rename AppLogo.vue
inside the components
directory to Navbar.vue
and replace it content with the following:
现在,让我们创建Navbar组件。 将components
目录内的AppLogo.vue
重命名为Navbar.vue
并将其内容替换为以下内容:
<template>
<nav class="navbar is-light">
<div class="container">
<div class="navbar-brand">
<nuxt-link class="navbar-item" to="/">Nuxt Auth</nuxt-link>
<button class="button navbar-burger">
<span></span>
<span></span>
<span></span>
</button>
</div>
<div class="navbar-menu">
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
My Account
</a>
<div class="navbar-dropdown">
<nuxt-link class="navbar-item" to="/profile">My Profile</nuxt-link>
<hr class="navbar-divider">
<a class="navbar-item">Logout</a>
</div>
</div>
<nuxt-link class="navbar-item" to="/register">Register</nuxt-link>
<nuxt-link class="navbar-item" to="/login">Log In</nuxt-link>
</div>
</div>
</div>
</nav>
</template>
The Navbar component contains links to login or register, links to view profile or logout.
导航栏组件包含用于登录或注册的链接,用于查看配置文件或注销的链接。
Next, let’s update the default layout to make use of the Navbar
component. Open layouts/default.vue
and replace its content with the following:
接下来,让我们更新默认布局以使用Navbar
组件。 打开layouts/default.vue
并将其内容替换为以下内容:
<template>
<div>
<Navbar/>
<nuxt/>
</div>
</template>
<script>
import Navbar from '~/components/Navbar'
export default {
components: {
Navbar
}
}
</script>
Also, let’s update the homepage. Open pages/index.vue
and replace its content with the following:
另外,让我们更新主页。 打开pages/index.vue
并将其内容替换为以下内容:
<template>
<section class="section">
<div class="container">
<h1 class="title">Nuxt Auth</h1>
</div>
</section>
</template>
Our app should now look something similar to below:
现在,我们的应用程序应类似于以下内容:
Inside the pages
directory, create a new register.vue
file and paste the code below in it:
在pages
目录中,创建一个新的register.vue
文件,并将以下代码粘贴到其中:
<template>
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-4 is-offset-4">
<h2 class="title has-text-centered">Register!</h2>
<Notification :message="error" v-if="error"/>
<form method="post" @submit.prevent="register">
<div class="field">
<label class="label">Username</label>
<div class="control">
<input
type="text"
class="input"
name="username"
v-model="username"
required
>
</div>
</div>
<div class="field">
<label class="label">Email</label>
<div class="control">
<input
type="email"
class="input"
name="email"
v-model="email"
required
>
</div>
</div>
<div class="field">
<label class="label">Password</label>
<div class="control">
<input
type="password"
class="input"
name="password"
v-model="password"
required
>
</div>
</div>
<div class="control">
<button type="submit" class="button is-dark is-fullwidth">Register</button>
</div>
</form>
<div class="has-text-centered" style="margin-top: 20px">
Already got an account? <nuxt-link to="/login">Login</nuxt-link>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import Notification from '~/components/Notification'
export default {
components: {
Notification,
},
data() {
return {
username: '',
email: '',
password: '',
error: null
}
},
methods: {
async register() {
try {
await this.$axios.post('register', {
username: this.username,
email: this.email,
password: this.password
})
await this.$auth.loginWith('local', {
data: {
email: this.email,
password: this.password
},
})
this.$router.push('/')
} catch (e) {
this.error = e.response.data.message
}
}
}
}
</script>
This contains a form with three fields: username, email, and password. Each field is bound to a corresponding data on the component. When the form is submitted, a register
method will be called. Using the Axios module, we make a post request to the /register
endpoint, passing along the user data. If the registration was successful, we make use of the Auth module’s loginWith()
, using the local
strategy and passing the user data to log the user in. Then we redirect the user to the homepage. If there is an error during the registration, we set the error
data as the error message gotten from the API response.
它包含具有三个字段的表单:用户名,电子邮件和密码。 每个字段都绑定到组件上的相应数据。 提交表单后,将调用一个register
方法。 使用Axios模块,我们向/register
端点发出发布请求,并传递用户数据。 如果注册成功,我们将使用Auth模块的loginWith()
,并使用local
策略并传递用户数据以登录用户。然后,将用户重定向到首页。 如果在注册过程中出现错误,我们将error
数据设置为从API响应中获得的错误消息。
If there is an error, the error message is displayed by a Notification component, which we’ll create shortly.
如果有错误,错误消息将由Notification组件显示,我们将在不久后创建该组件。
Before we test the user registration out, let’s create the Notification component. Create a new Notification.vue
file inside components
and paste the code below in it:
在测试用户注册之前,让我们创建通知组件。 在components
内部创建一个新的Notification.vue
文件,并将以下代码粘贴到其中:
<template>
<div class="notification is-danger">
{{ message }}
</div>
</template>
<script>
export default {
name: 'Notification',
props: ['message']
}
</script>
The Notification component accepts a message
props, which is the error message.
Notification组件接受一条message
props,即错误消息。
Now, we can test out user registration:
现在,我们可以测试用户注册:
Upon successful registration, we should be logged in but there is no way for us to know whether we are logged in or not for now. So let’s fix that by updating the Navbar component and adding some computed properties.
成功注册后,我们应该已经登录,但是目前没有办法让我们知道是否登录。 因此,让我们通过更新Navbar组件并添加一些计算出的属性来解决此问题。
Before we do just that, let’s first activate the Vuex store by creating an index.js
file inside the store
directory. The Auth module stores user authentication status as well as user details inside Vuex state in an auth
object. So we can check if a user is logged in or not with this.$store.state.auth.loggedIn
, which will either return true
or false
. Similarly, we can get a user’s details with this.$store.state.auth.user
, which will be null
if no user is logged in.
在执行此操作之前,我们首先通过在store
目录中创建index.js
文件来激活Vuex商店。 Auth模块将用户身份验证状态以及用户详细信息存储在auth
对象中的Vuex状态内。 因此,我们可以使用this.$store.state.auth.loggedIn
检查用户是否登录,该用户返回true
或false
。 同样,我们可以使用this.$store.state.auth.user
获取用户的详细信息,如果没有用户登录,则该this.$store.state.auth.user
为null
。
NOTE: We can also access the user authentication status as well as the user details directly with the Auth module using this.$auth.loggedIn
and this.$auth.user
respectively.
注意:我们还可以分别使用this.$auth.loggedIn
和this.$auth.user
通过Auth模块直接访问用户身份验证状态和用户详细信息。
Since we might want to use the computed properties in multiple places in our app, let’s create store getters. Paste the code below into store/index.js
:
由于我们可能想在应用程序中的多个位置使用计算所得的属性,因此让我们创建商店吸气剂。 将以下代码粘贴到store/index.js
:
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn
},
loggedInUser(state) {
return state.auth.user
}
}
Here, we create two getters. The first one (isAuthenticated
) will return the authentication status of a user and the second (loggedInUser
) will return the details or the logged in user.
在这里,我们创建两个吸气剂。 第一个( isAuthenticated
)将返回用户的身份验证状态,第二个( loggedInUser
)将返回详细信息或已登录的用户。
Next, let’s update the Navbar component to make use of the getters. Replace the content of components/Navbar.vue
with the following:
接下来,让我们更新Navbar组件以利用吸气剂。 用以下内容替换components/Navbar.vue
的内容:
<template>
<nav class="navbar is-light">
<div class="container">
<div class="navbar-brand">
<nuxt-link class="navbar-item" to="/">Nuxt Auth</nuxt-link>
<button class="button navbar-burger">
<span></span>
<span></span>
<span></span>
</button>
</div>
<div class="navbar-menu">
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable" v-if="isAuthenticated">
<a class="navbar-link">
{{ loggedInUser.username }}
</a>
<div class="navbar-dropdown">
<nuxt-link class="navbar-item" to="/profile">My Profile</nuxt-link>
<hr class="navbar-divider">
<a class="navbar-item">Logout</a>
</div>
</div>
<template v-else>
<nuxt-link class="navbar-item" to="/register">Register</nuxt-link>
<nuxt-link class="navbar-item" to="/login">Log In</nuxt-link>
</template>
</div>
</div>
</div>
</nav>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['isAuthenticated', 'loggedInUser'])
}
}
</script>
We create the computed properties by using the spread operator (…
) to extract the getters from mapGetters
. Then using isAuthenticated
, we display the user menu or links to login or register depending on whether the user is logged in or not. Also, we use loggedInUser
to display the authenticated user username.
我们通过使用散布运算符( …
)从mapGetters
提取吸气剂来创建计算属性。 然后,使用isAuthenticated
,根据用户是否登录,显示用户菜单或用于登录或注册的链接。 另外,我们使用loggedInUser
显示经过身份验证的用户名。
Now, if we give our app a refresh, we should see something similar to below:
现在,如果我们刷新应用程序,我们应该会看到类似于以下内容:
Now let’s allow returning users ability to log in. Create a new login.vue
file inside the pages
directory and paste the code below in it:
现在,让login.vue
用户能够登录。在pages
目录中创建一个新的login.vue
文件,并将以下代码粘贴到其中:
<template>
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-4 is-offset-4">
<h2 class="title has-text-centered">Welcome back!</h2>
<Notification :message="error" v-if="error"/>
<form method="post" @submit.prevent="login">
<div class="field">
<label class="label">Email</label>
<div class="control">
<input
type="email"
class="input"
name="email"
v-model="email"
>
</div>
</div>
<div class="field">
<label class="label">Password</label>
<div class="control">
<input
type="password"
class="input"
name="password"
v-model="password"
>
</div>
</div>
<div class="control">
<button type="submit" class="button is-dark is-fullwidth">Log In</button>
</div>
</form>
<div class="has-text-centered" style="margin-top: 20px">
<p>
Don't have an account? <nuxt-link to="/register">Register</nuxt-link>
</p>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import Notification from '~/components/Notification'
export default {
components: {
Notification,
},
data() {
return {
email: '',
password: '',
error: null
}
},
methods: {
async login() {
try {
await this.$auth.loginWith('local', {
data: {
email: this.email,
password: this.password
}
})
this.$router.push('/')
} catch (e) {
this.error = e.response.data.message
}
}
}
}
</script>
This is quite similar to the register
page. The form contains two fields: email and password. When the form is submitted, a login
method will be called. Using the Auth module loginWith()
and passing along the user data, we log the user in. If the authentication was successful, we redirect the user to the homepage. Otherwise set error
to the error message gotten from the API response. Again, we are using the Notification component from earlier on to display the error message.
这与register
页面非常相似。 该表格包含两个字段:电子邮件和密码。 提交表单后,将调用login
方法。 使用Auth模块loginWith()
并传递用户数据,我们使用户登录。如果身份验证成功,则将用户重定向到主页。 否则,将error
设置为从API响应获得的错误消息。 同样,我们从较早开始就使用Notification组件显示错误消息。
Let’s allow logged in users to view their profile. Create a new profile.vue
file inside the pages
directory and paste the code below in it:
让我们允许登录的用户查看其个人资料。 在pages
目录中创建一个新的profile.vue
文件,并将以下代码粘贴到其中:
<template>
<section class="section">
<div class="container">
<h2 class="title">My Profile</h2>
<div class="content">
<p>
<strong>Username:</strong>
{{ loggedInUser.username }}
</p>
<p>
<strong>Email:</strong>
{{ loggedInUser.email }}
</p>
</div>
</div>
</section>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['loggedInUser'])
}
}
</script>
We are using the loggedInUser
getter from earlier on to display display the user details.
我们从较早开始就使用了loggedInUser
getter来显示用户详细信息。
Clicking on the My Profile link should result in a My Profile page being displayed.
单击“ 我的个人资料”链接应导致显示“ 我的个人资料”页面。
Update the logout link inside the Navbar component as below:
更新导航栏组件内的注销链接,如下所示:
<a class="navbar-item" @click="logout">Logout</a>
When the logout link is click, it will trigger a logout
method.
单击注销链接时,将触发logout
方法。
Next, let’s add the logout
method inside the script section of the Navbar component:
接下来,让我们在Navbar组件的脚本部分内添加logout
方法:
methods: {
async logout() {
await this.$auth.logout();
},
},
We call the logout()
of the Auth module. This will delete the user’s token from localstorage and redirect the user to the homepage.
我们调用Auth模块的logout()
。 这将从本地存储中删除用户的令牌,并将用户重定向到主页。
As it stands now, anybody can visit the profile
page and if the user is not logged in, it will result in error.
目前,任何人都可以访问profile
页面,如果用户未登录,将导致错误。
To fix this, we need to restrict the profile page to only logged in users. Luckily for us, we can achieve that with the Auth module. The Auth module comes with an auth
middleware, which we can use in this scenario.
要解决此问题,我们需要将个人资料页面限制为仅已登录的用户。 幸运的是,我们可以使用Auth模块来实现。 Auth模块附带一个auth
中间件,我们可以在这种情况下使用它。
So let’s add the auth
middleware to the profile
page, update the script section as below:
因此,让我们将auth
中间件添加到profile
页面,如下更新脚本部分:
<script>
...
export default {
middleware: 'auth',
...
}
</script>
Now when a user that is not logged in tries to visit the profile
page, the user will be redirected to the login
page.
现在,当未登录的用户尝试访问profile
页面时,该用户将被重定向到login
页面。
Again as it stand, even as a logged in user, we can still access the login and register pages. One way to fix that is to restrict login and register pages to only users that are not logged in. We can do that by creating a guest middleware. Inside the middleware
directory, create a new guest.js
file and paste the code below in it:
照原样,即使作为登录用户,我们仍然可以访问登录页面和注册页面。 一种解决方法是将登录和注册页面限制为仅未登录的用户。我们可以通过创建来宾中间件来做到这一点。 在middleware
目录中,创建一个新的guest.js
文件,并将以下代码粘贴到其中:
export default function ({ store, redirect }) {
if (store.state.auth.loggedIn) {
return redirect('/')
}
}
A middleware accepts the context as its first argument. So we extract store
and redirect
from the context. We check if the user is logged in then redirect the user to the homepage. Otherwise, we allow the normal execution of the request.
中间件接受上下文作为其第一个参数。 因此,我们提取store
并从上下文redirect
。 我们检查用户是否已登录,然后将用户重定向到主页。 否则,我们将允许请求的正常执行。
Next, let’s make use of this middleware. Update the script section of both login
and register
as below:
接下来,让我们利用这个中间件。 更新login
和register
的脚本部分,如下所示:
<script>
...
export default {
middleware: 'guest',
...
}
</script>
Now everything will be working as expected.
现在一切都会按预期进行。
In this tutorial, we looked at how to implement authentication in a Nuxt.js application using the Auth module. We also saw how to keep the authentication flow sleek by making use of middleware.
在本教程中,我们研究了如何使用Auth模块在Nuxt.js应用程序中实现身份验证。 我们还看到了如何通过使用中间件来保持认证流程的流畅。
To learn more and the Auth module, checkout the docs.
要了解更多信息和Auth模块,请查看docs 。
翻译自: https://www.digitalocean.com/community/tutorials/implementing-authentication-in-nuxtjs-app
nuxt.js 全局 js