本文转载自微信公众号「新钛云服」,作者李冰。转载本文请联系新钛云服公众号。
身份验证(登录!)是许多网站的重要组成部分。让我们看看如何使用Vue在网站上进行处理,其方式与在任何自定义后端中进行处理的方式相同。Vue实际上不能完全自己进行身份验证,为此我们需要另一个服务,因此我们将为此使用另一个服务(Firebase),然后将整个体验整合到Vue中。
身份验证在单页应用程序(SPA)上的工作方式与在重新加载每个页面的站点上的工作方式完全不同。
我们将构建一个用户登录界面,并将提交的数据发送到服务器以检查用户是否存在。如果是,我们将收到令牌。这非常有用,因为它将在我们的整个站点中用于检查用户是否仍在登录。如果没有,则用户可以随时注册。换句话说,它可以在许多条件上下文中使用。除此之外,如果我们需要来自服务器的任何需要登录的信息,则令牌将通过URL发送到服务器,以便仅将信息发送给登录的用户。
本教程的完整演示已发布在 GitHub 上, 以供那些熟悉 阅读代码的人使用。我们其余的人可以继续阅读本文。起始文件也位于 GitHub 上, 因此您可以在我们一起编码时继续进行操作。
下载后,您将npm install在终端中运行。如果要完全自己构建此应用程序,则必须安装Vuex ,Vue Router 和axios 。我们还将在该项目中使用Firebase ,因此花点时间设置一个免费帐户并在其中创建一个新项目。
将项目添加到Firebase后,转到身份验证部分,并设置登录方法,该方法将使用传统的电子邮件/密码提供程序,该方法将存储在Firebase服务器上。
之后,我们将转到Firebase Auth REST API 文档 获取我们的注册并登录API端点。我们需要一个API密钥才能在我们的应用程序中使用这些终结点,并且可以在Firebase项目设置中找到它。
Firebase通过SDK提供身份验证,但是我们使用Auth API来演示通过任何自定义后端服务器进行的身份验证。
在我们的状态报告文件中,下面有注册表格。由于我们专注于学习概念,因此我们在这里使事情保持简单。
- <template>
- <div id="signup">
- <div class="signup-form">
- <form @submit.prevent="onSubmit">
- <div class="input">
- <label for="email">Mail</label>
- <input
- type="email"
- id="email"
- v-model="email">
- </div>
- <div class="input">
- <label for="name">Your Name</label>
- <input
- type="text"
- id="name"
- v-model.number="name">
- </div>
- <div class="input">
- <label for="password">Password</label>
- <input
- type="password"
- id="password"
- v-model="password">
- </div>
- <div class="submit">
- <button type="submit">Submit</button>
- </div>
- </form>
- </div>
- </div>
- </template>
如果我们不使用SPA,我们自然会使用axios将数据发送到script标签中,如下所示:
- axios.post('https://identitytoolkit.googleapis.com/v1/account
- s:signUp?key=[API_KEY]',{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- })
- .catch(error => console.log(error))
- }
- }
注册并登录
使用SPA(在这种情况下使用Vue)与上述方法非常不同。相反,我们将在文件中的操作中使用Vuex 发送授权请求store.js。我们这样做是因为我们希望整个应用程序都知道用户身份验证状态的任何更改。
- actions:{
- signup ({commit},authData){
- axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]',{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- },
- login ({commit},authData){
- axios.post(https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]',{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- }
- }
我们可以对登录方法使用几乎相同的东西,但是可以使用登录API端点代替。然后,我们将组件的注册和登录分派到商店中它们各自的操作。
- methods :{
- onSubmit (){
- constformData ={
- email :this.email,
- name :this.name,
- password :this.password
- }
- this.$store.dispatch('signup',formData)
- }
- }
- }
formData 包含用户的数据。
- methods : {
- onSubmit () {
- const formData = {
- email : this.email,
- password : this.password
- }
- this.$store.dispatch('login', {email: formData.email, password: formData.password})
- }
- }
我们将接收从注册/登录表单中收到的身份验证数据(即令牌和用户ID),并将其用作Vuex的状态。最初的结果为null。
- state:{
- idToken:null,
- userId:null,
- user:null
- }
现在,我们authUser在突变中创建一个称为的新方法,该方法将存储从响应中收集的数据。我们需要将路由器导入商店,因为稍后需要。
- import router from'/router'
- mutations :{
- authUser (state,userData){
- state.idToken =userData.token
- state.userId =userData.userId
- }
- }
.then在我们的操作的signup / login方法中的块内,我们将对authUser刚刚创建的变异的响应提交并保存到本地存储中。
- actions:{
- signup ({commit},authData){
- axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]'),{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- commit('authUser',{
- token:res.data.idToken,
- userId:res.data.localId
- })
- localStorage.setItem('token',res.data.idToken)
- localStorage.setItem('userId',res.data.localId)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- },
- login ({commit},authData){
- axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]'),{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- commit('authUser',{
- token:res.data.idToken,
- userId:res.data.localId
- })
- localStorage.setItem('token',res.data.idToken)
- localStorage.setItem('userId',res.data.localId)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- }
- }
设置身份验证防护
现在我们已经将令牌存储在应用程序中,接下来将在设置Auth Guard时使用该令牌。什么是Auth Guard?它可以保护仪表板,防止未经身份验证的用户访问没有令牌的仪表板。
首先,我们将进入路线文件并导入商店。由于令牌将确定用户的登录状态,因此导入了商店。
- import store from'./store.js'
那么,我们的路线阵列内,去到仪表板路径,添加方法beforeEnter这个方法有三个参数:to,from和next。在这种方法中,我们只是简单地说,如果存储了令牌(如果通过身份验证,令牌将自动完成),那么next,意味着令牌将沿着指定的路线继续。否则,我们会将未经身份验证的用户带回注册页面。
- {
- path:'/dashboard',
- component:DashboardPage,
- beforeEnter (to,from, next){
- if(store.state.idToken){
- next()
- }
- else{
- next('/signin')
- }
- }
- }
创建UI状态
此时,无论是否登录,我们仍然可以在导航中看到仪表板,这不是我们想要的。我们必须在调用的getters下添加另一个方法,该方法ifAuthenticated检查状态中的令牌是否为null,然后相应地更新导航项。
- getters:{
- user (state){
- returnstate.user
- },
- ifAuthenticated (state){
- returnstate.idToken !==null
- }
- }
接下来,让我们打开标题组件,并auth在computed属性内部创建一个称为方法。这将分派给ifAuthenticated我们刚刚在商店中创建的吸气剂。如果没有令牌,ifAuthenticated将返回false,这自动意味着auth也将是null,反之亦然。在这之后,我们添加了一个v-if检查,如果auth是null或不是,确定仪表盘选项是否会显示在导航。
- <template>
- <header id="header">
- <div class="logo">
- <router-link to="/">Vue Authenticate</router-link>
- </div>
- <nav>
- <ul>
- <li v-if='auth'>
- <router-link to="/dashboard">Dashboard</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signup">Register</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signin">Log In</router-link>
- </li>
- </ul>
- </nav>
- </header>
- </template>
- <script>
- exportdefault{
- computed:{
- auth (){
- returnthis.$store.getters.ifAuthenticated
- }
- },
- }
- </script>
注销
没有注销按钮的应用程序是什么?让我们创建一个名为的新突变clearAuth,它将令牌和都设置userId为null。
- mutations:{
- authUser (state,userData){
- state.idToken =userData.token
- state.userId =userData.userId
- },
- clearAuth (state){
- state.idToken =null
- state.userId =null
- }
- }
然后,在我们的logout操作中,我们承诺clearAuth,删除本地存储并添加router.replace('/')以在注销后正确地重定向用户。
返回标题组件。我们有一种onLogout方法可以logout在商店中调度我们的行动。然后,我们@click在按钮中添加一个,该按钮将调用onLogout方法,如下所示:
- <template>
- <header id="header">
- <div class="logo">
- <router-link to="/">Vue Authenticate</router-link>
- </div>
- <nav>
- <ul>
- <li v-if='auth'>
- <router-link to="/dashboard">Dashboard</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signup">Register</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signin">Log In</router-link>
- </li>
- <li v-if='auth'>
- <ul @click="onLogout">Log Out</ul>
- </li>
- </ul>
- </nav>
- </header>
- </template>
- <script>
- exportdefault{
- computed:{
- auth (){
- returnthis.$store.getters.ifAuthenticated
- }
- },
- methods:{
- onLogout(){
- this.$store.dispatch('logout')
- }
- }
- }
- </script>
自动登录?当然!
我们的应用程序差不多完成了。我们可以使用刚刚完成的所有UI更改进行注册,登录和注销。但是,当我们刷新应用程序时,我们会丢失数据并注销,必须重新开始,因为我们将令牌和ID存储在JavaScript的Vuex中。这意味着刷新后,应用程序中的所有内容都会重新加载到浏览器中。
我们要做的是在本地存储中检索令牌。这样,无论何时刷新窗口,我们都可以在浏览器中拥有用户的令牌,只要令牌仍然有效,甚至可以自动登录用户。
创建一个名为的新动作方法,仅当用户拥有AutoLogin令牌时,我们才能userId从本地存储中获取令牌。然后,我们将数据提交给authUser突变中的方法。
- actions :{
- AutoLogin ({commit}){
- const token =localStorage.getItem('token')
- if(!token){
- return
- }
- constuserId =localStorage.getItem('userId')
- const token =localStorage.getItem('token')
- commit('authUser',{
- idToken: token,
- userId:userId
- })
- }
然后,我们转到我们App.vue的created方法,并在autoLogin加载应用程序时从商店中分发。
- created (){
- this.$store.dispatch('AutoLogin')
- }
好极了!这样,我们就可以在应用程序内成功实现身份验证,现在可以使用进行部署npm run build。观看现场演示 以观看实际操作。
原文: https://css-tricks.com/tackling-authentication-with-vue-using-restful-apis/