本文共 17155 字,大约阅读时间需要 57 分钟。
vue中使用vuex
Traditionally, many people use local storage to manage tokens generated through client-side authentication. A big concern is always a better way to manage authorization tokens to allow us to store even more information on users.
传统上,许多人使用本地存储来管理通过客户端身份验证生成的令牌。 人们始终关心的一个更好的方法是管理授权令牌,以使我们能够在用户上存储更多信息。
This is where comes in. Vuex manages states for applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.
这就是进入的地方管理应用程序的状态。 它充当应用程序中所有组件的集中存储,其规则确保状态只能以可预测的方式进行更改。
Sounds like a better alternative to always checking localStorage? Let’s explore it.
听起来像是始终检查localStorage的更好的选择? 让我们来探索它。
For this project, we want to create a vue application that has vuex and . We will use the vue cli 3.0 to create a new vue project and select router and vuex from the options.
对于此项目,我们要创建一个具有vuex和的vue应用程序。 我们将使用vue cli 3.0创建一个新的vue项目,并从选项中选择router和vuex。
Run the following command to set it up:
运行以下命令进行设置:
$ vue create vue-auth
Follow the dialogue that shows up, add the necessary information and select the options we need and complete the installation.
按照出现的对话框,添加必要的信息,然后选择我们需要的选项并完成安装。
Next, install :
接下来,安装 :
$npm install axios --save
We will need axios across many of our components. Let’s set it up at the entry level so we do not have to import it every time we need it.
我们将需要在许多组件中使用axios。 让我们在入门级进行设置,这样就不必每次都需要导入它。
Open the ./src/main.js
file and add the following:
打开./src/main.js
文件并添加以下内容:
[...]import store from './store'import Axios from 'axios'Vue.prototype.$http = Axios;const token = localStorage.getItem('token')if (token) { Vue.prototype.$http.defaults.headers.common['Authorization'] = token}[...]
Now, when we want to use axios inside our component, we can do this.$http
and it will be like calling axios directly. We also set the Authorization
on axios header to our token, so our requests can be processed if a token is required. This way, we do not have to set token anytime we want to make a request.
现在,当我们想在组件内部使用axios时,可以执行this.$http
就像直接调用axios。 我们还将axios标头上的Authorization
设置为令牌,因此如果需要令牌,则可以处理我们的请求。 这样,我们不必在要发出请求的任何时间设置令牌。
When that is done, let’s set up the server to handle authentication.
完成后,让我们设置服务器以处理身份验证。
I already wrote about this when explaining how to handle authentication with vue-router. Check out the section of this
在解释如何使用vue-router进行身份验证时,我已经写过有关此内容的文章。 查看本节的“ 部分
Create a file Login.vue
in the ./src/components
directory. Then, add the template for the login page:
在./src/components
目录中创建一个文件Login.vue
。 然后,为登录页面添加模板:
When you are done, add the data attributes that would bind to the HTML form:
完成后,添加将绑定到HTML表单的数据属性:
[...]
Now, let’s add the method for handling login:
现在,让我们添加用于处理登录的方法:
[...]
We are using a vuex action — login
to handle this authentication. We can resolve actions into promises so we can do cool things with them inside our component.
我们正在使用vuex操作- login
以处理此身份验证。 我们可以将行动分解为承诺,这样我们就可以在组件内部用它们来做一些很棒的事情。
Like the component for login, let’s make one for registering users. Start by creating a file Register.vue
in the components directory and add the following to it:
像用于登录的组件一样,让我们制作一个用于注册用户的组件。 首先在components目录中创建一个文件Register.vue
,并将以下内容添加到其中:
Register
Let define the data attributes we will bind to the form:
让我们定义将绑定到表单的数据属性:
[...]
Now, let’s add the method for handling login:
现在,让我们添加用于处理登录的方法:
[...]
Let’s make a simple component that would only display if our user is authenticated. Create the component file Secure.vue
and add the following to it:
让我们做一个简单的组件,该组件仅在我们的用户通过身份验证时才会显示。 创建组件文件Secure.vue
并添加以下内容:
This page is protected by auth
Open ./src/App.vue
file and add the following to it:
打开./src/App.vue
文件,然后向其中添加以下内容:
Can you see the Logout
link we set to only show up if a user is logged in? Great.
您能看到我们设置为仅在用户登录后才显示的Logout
链接吗? 大。
Now, let’s add the logic behind the log out:
现在,让我们在注销后添加逻辑:
We are doing two things — computing the authentication state of the user and dispatching a logout action to our vuex store when a user clicks the logout button. After the log out, we send the user to login
page using this.$router.push('/login')
. You can change where the user gets sent to if you want.
我们正在做两件事–计算用户的身份验证状态,并在用户单击注销按钮时将注销操作分派到我们的vuex存储。 注销后,我们使用this.$router.push('/login')
将用户发送到login
页面。 您可以根据需要更改将用户发送到的位置。
That’s it. Let’s make the auth module using vuex.
而已。 让我们使用vuex创建auth模块。
If you read past the ****section, you would notice we had to store user auth token in localStorage and we had to retrieve both the token and user information anytime we wanted to check if the user is authenticated. This works, but it is not really elegant. We will rebuild the authentication to use vuex.
如果您阅读了 ****部分的内容,您会发现我们必须将用户身份验证令牌存储在localStorage中,并且无论何时要检查用户是否已通过身份验证,都必须同时检索令牌和用户信息。 这行得通,但并不是很优雅。 我们将重建身份验证以使用vuex。
First, let’s setup our store.js
file for vuex:
首先,让我们为vuex设置store.js
文件:
import Vue from 'vue'import Vuex from 'vuex'import axios from 'axios'Vue.use(Vuex)export default new Vuex.Store({ state: { status: '', token: localStorage.getItem('token') || '', user : { } }, mutations: { }, actions: { }, getters : { }})
If you noticed, we have imported vue, vuex and axios, then asked vue to use vuex. This is because we mean serious business here.
如果您注意到,我们已经导入了vue,vuex和axios,然后要求vue使用vuex。 这是因为我们的意思是认真的生意。
We have defined the attributes of the state. Now the vuex state would hold our authentication status, jwt
token and user information.
我们已经定义了状态的属性。 现在,vuex状态将保留我们的身份验证状态, jwt
令牌和用户信息。
login
操作 (Create The Vuex login
Action)Vuex actions are used to commit mutations to the vuex store. We will create a login
action that would authenticate a user with the server and commit user credentials to the vuex store. Open the ./src/store.js
file and add the following to actions object:
Vuex操作用于将变异提交到vuex存储。 我们将创建一个login
操作,该操作将对服务器进行用户身份验证并将用户凭据提交给vuex存储。 打开./src/store.js
文件,并将以下内容添加到action对象:
login({ commit}, user){ return new Promise((resolve, reject) => { commit('auth_request') axios({ url: 'http://localhost:3000/login', data: user, method: 'POST' }) .then(resp => { const token = resp.data.token const user = resp.data.user localStorage.setItem('token', token) axios.defaults.headers.common['Authorization'] = token commit('auth_success', token, user) resolve(resp) }) .catch(err => { commit('auth_error') localStorage.removeItem('token') reject(err) }) })},
The login action passes vuex commit
helper that we will use to trigger mutations. Mutations make changes to vuex store.
登录操作传递了vuex commit
助手,我们将使用它来触发突变。 变异会更改vuex存储。
We are making a call to the server’s login route and returning the necessary data. We store the token on localStorage, then pass the token and user information to auth_success
to update the store’s attributes. We also set the header for axios
at this point as well.
我们正在拨打服务器的登录路由,并返回必要的数据。 我们将令牌存储在localStorage上,然后将令牌和用户信息传递给auth_success
来更新商店的属性。 在这一点上,我们还为axios
设置了标头。
We could store the token in vuex store, but if the user leaves our application, all of the data in the vuex store disappears. To ensure we allow the user to return to the application within the validity time of the token and not have to log in again, we have to keep the token in localStorage.
我们可以将令牌存储在vuex存储中,但是如果用户离开我们的应用程序,则vuex存储中的所有数据都会消失。 为确保我们允许用户在令牌的有效期内返回应用程序而不必再次登录,我们必须将令牌保留在localStorage中。
It’s important you know how these work so you can decide what exactly it is you want to achieve.
了解这些工作原理非常重要,这样您就可以决定要实现的目标。
We return a promise so we can return a response to a user after login is complete.
我们返回承诺,因此我们可以在登录完成后将响应返回给用户。
register
操作 (Create The Vuex register
Action)Like the login
action, the register
action will work almost the same way. In the same file, add the following in the actions object:
像login
操作一样, register
操作的工作方式几乎相同。 在同一文件中,在action对象中添加以下内容:
register({ commit}, user){ return new Promise((resolve, reject) => { commit('auth_request') axios({ url: 'http://localhost:3000/register', data: user, method: 'POST' }) .then(resp => { const token = resp.data.token const user = resp.data.user localStorage.setItem('token', token) axios.defaults.headers.common['Authorization'] = token commit('auth_success', token, user) resolve(resp) }) .catch(err => { commit('auth_error', err) localStorage.removeItem('token') reject(err) }) })},
This works similarly to login
action, calling the same mutators as our login
and register
actions have the same simple goal — get a user into the system.
这与login
操作类似,其调用方式与我们的login
和register
操作具有相同的简单目标—使用户进入系统。
logout
操作 (Create The Vuex logout
Action)We want the user to have the ability to log out of the system, and we want to destroy all data created during the last authenticated session. In the same actions
object, add the following:
我们希望用户具有注销系统的能力,并且希望销毁在上次身份验证会话期间创建的所有数据。 在同一actions
对象中,添加以下内容:
logout({ commit}){ return new Promise((resolve, reject) => { commit('logout') localStorage.removeItem('token') delete axios.defaults.headers.common['Authorization'] resolve() })}
Now, when the user clicks to log out, we will remove the jwt
token we stored along with the axios
header we set. There is no way they can perform a transaction requiring a token now.
现在,当用户单击注销时,我们将删除存储的jwt
令牌以及设置的axios
标头。 他们现在无法执行需要令牌的交易。
Like I mentioned earlier, mutators are used to change the state of a vuex store. Let’s define the mutators we had used throughout our application. In the mutators object, add the following:
就像我之前提到的那样,mutator用于更改vuex存储的状态。 让我们定义在整个应用程序中使用的转换器。 在mutators对象中,添加以下内容:
mutations: { auth_request(state){ state.status = 'loading' }, auth_success(state, token, user){ state.status = 'success' state.token = token state.user = user }, auth_error(state){ state.status = 'error' }, logout(state){ state.status = '' state.token = '' },},
We use getter to get the value of the attributes of vuex state. The role of our getter in the situation is to separate application data from application logic and ensure we do not give away sensitive information.
我们使用getter获取vuex状态的属性值。 在这种情况下,我们的吸气剂的作用是将应用程序数据与应用程序逻辑分开,并确保我们不会泄露敏感信息。
Add the following to the getters
object:
将以下内容添加到getters
对象:
getters: { isLoggedIn: state => !!state.token, authStatus: state => state.status,}
You would agree with me that this is a neater way to access data in the store ☺️.
您会同意我的看法,这是一种访问商店☺️中的数据的更整洁的方式。
The whole purpose of this article is to implement authentication and keep certain pages away from a user who is not authentication. To achieve this, we need to know the page the user wants to visit and equally have a way to check if the user is authenticated. We also need a way to say if the page is reserved for only authenticated user or unauthenticated user alone or both. These things are important considerations which, luckily, we can achieve with vue-router.
本文的全部目的是实现身份验证,并使某些页面远离非身份验证用户。 为此,我们需要知道用户想要访问的页面,并且同样具有一种检查用户是否已通过身份验证的方法。 我们还需要一种方法来说明页面是仅保留给已认证的用户还是仅保留给未认证的用户,或者两者都保留。 这些东西是重要的考虑因素,幸运的是,我们可以使用vue-router实现这些考虑。
Open the ./src/router.js
file and import what we need for this setup:
打开./src/router.js
文件,并导入此设置所需的内容:
import Vue from 'vue'import Router from 'vue-router'import store from './store.js'import Home from './views/Home.vue'import About from './views/About.vue'import Login from './components/Login.vue'import Secure from './components/Secure.vue'import Register from './components/Register.vue'Vue.use(Router)
As you can see, we have imported vue, vue-router and our vuex store setup. We also imported all the components we defined and set vue to use our router.
如您所见,我们已经导入了vue,vue-router和我们的vuex存储设置。 我们还导入了我们定义的所有组件,并设置了vue以使用我们的路由器。
Let’s define the routes:
让我们定义路线:
[...]let router = new Router({ mode: 'history', routes: [ { path: '/', name: 'home', component: Home }, { path: '/login', name: 'login', component: Login }, { path: '/register', name: 'register', component: Register }, { path: '/secure', name: 'secure', component: Secure, meta: { requiresAuth: true } }, { path: '/about', name: 'about', component: About } ]})export default router
Our route definition is simple. For routes requiring authentication, we add extra data to it to enable us identify it when the user tries to access it. This is the essence of the meta
attribute added to the route definition. If you are asking ”Can I add more data to this meta
and use it?” then I’m pleased to tell you that you are absolutely right ?.
我们的路线定义很简单。 对于需要身份验证的路由,我们向其中添加了额外的数据,以使我们能够在用户尝试访问它时对其进行识别。 这是添加到路由定义的meta
属性的本质。 如果您问“我可以向此 meta
数据添加更多数据 并使用它吗?” 那我很高兴地告诉你,你绝对正确吗?
We have our routes defined. Now, let’s check for unauthorized access and take action. In the router.js
file, add the following before the export default router
:
我们定义了路线。 现在,让我们检查未经授权的访问并采取措施。 在router.js
文件中,在export default router
之前添加以下内容:
router.beforeEach((to, from, next) => { if(to.matched.some(record => record.meta.requiresAuth)) { if (store.getters.isLoggedIn) { next() return } next('/login') } else { next() }})
From the article on using vue router for authentication, you can recall we had a really complex mechanism here that grew very big and got very confusing. Vuex has helped us simplify that completely, and we can go on to add any condition to our route. In our vuex store, we can then define actions to check these conditions and getters to return them.
从有关使用vue路由器进行身份验证的文章中,您可以回忆起我们这里有一个非常复杂的机制,它变得非常大并且令人非常困惑。 Vuex帮助我们完全简化了这一过程,我们可以继续为路线添加任何条件。 然后,在我们的vuex存储中,我们可以定义操作来检查这些条件,并通过getter返回它们。
Because we store our token in localStorage, it can remain there perpetually. This means that whenever we open our application, it would automatically authenticate a user even if the token has expired. What would happen at most is that our requests would keep failing because of an invalid token. This is bad for user experience.
因为我们将令牌存储在localStorage中,所以它可以永久保留在那里。 这意味着,每当我们打开应用程序时,即使令牌已过期,它也会自动对用户进行身份验证。 最多会发生的是,由于令牌无效,我们的请求将继续失败。 这不利于用户体验。
Now, open ./src/App.vue
file and in the script, add the following to it:
现在,打开./src/App.vue
文件,并在脚本中添加以下内容:
export default { [...] created: function () { this.$http.interceptors.response.use(undefined, function (err) { return new Promise(function (resolve, reject) { if (err.status === 401 && err.config && !err.config.__isRetryRequest) { this.$store.dispatch(logout) } throw err; }); }); }}
We are intercepting axios call to determine if we get 401 Unauthorized
response. If we do, we dispatch the logout
action and the user gets logged out of the application. This takes them to the login
page like we designed earlier and they can log in again.
我们正在拦截axios调用,以确定是否收到401 Unauthorized
响应。 如果这样做,我们将分派logout
操作,并且用户将从应用程序中注销。 就像我们之前设计的那样,这会将他们带到login
页面,他们可以再次登录。
We can agree that this will greatly improve the user’s experience ☺️.
我们可以同意,这将大大改善用户的体验☺️。
From the previous article, you can see the significant changes that get made to our present application based the introduction of vuex. Now, we do not rely on checking the token all the time and having messing conditionals everywhere we go. We can simply use the vuex store to manage authentication state and proceed to check state in our application using only a few lines of code.
从上一篇文章中,您可以看到基于vuex的引入对我们当前的应用程序进行的重大更改。 现在,我们不再依赖于一直检查令牌并在我们到处都有混乱的条件。 我们可以简单地使用vuex存储管理身份验证状态,然后仅使用几行代码就可以检查应用程序中的状态。
I hope this helps you build better applications.
我希望这可以帮助您构建更好的应用程序。
翻译自:
vue中使用vuex
转载地址:http://ssuwd.baihongyu.com/