认证是一个重要的功能,对大多数现代网络应用需要的安全性至关重要。如果被破坏,它可能会将你的用户的数据暴露给错误的人,从而带来安全风险。许多现代Web应用程序不从头开始处理认证,而是使用Auth0,一个易于实施、可适应的认证和授权平台。
Auth0目前提供了一个SPA SDK来处理Vue中的认证。然后,文档中已有的Vue插件封装了SDK的功能,而SDK又提供了一个高级的API抽象,处理了很多认证实现的小细节。
在本教程中,你将学习如何使用Auth0、传统的Vuex和Vue Router来实现认证,而不是像上面解释的那样使用插件和SDK。最后,你将使用Vue和Auth0构建一个功能性的认证服务,并使用这些相同的过程在你选择的任何Web应用中实现认证。让我们开始吧!
安装Vue CLI
我们将使用Vue CLI来启动该项目。如果你的系统中已经安装了Vue CLI,你可以跳到下一节。
首先,你需要在你的系统上安装Vue CLI。你可以用这个命令全局安装它。
npm install -g @vue/cli
现在我们可以使用Vue CLI来创建我们的项目。用这个命令创建一个新项目。
vue create vue-sample-auth0
你会被要求选择一个预设。选择Manually select features ,然后选择Babel,Vuex,Router, 和Linter/Formatter 。
还会问你是否要使用History mode 作为Router - 选择Yes 。你可以选择你想要的任何Linter,但在本教程中我将使用ESLint和Prettier。
项目创建完成后,导航到新的项目文件夹。
cd vue-sample-auth0
然后启动服务器。
npm run serve
一旦服务器启动,你就可以打开浏览器来查看。你应该看到这个。
设置Auth0
我们现在要安装Auth0的库来处理客户端的认证。
npm i auth0-js
要开始使用Auth0,你需要注册,创建一个新租户,并选择你的地区。然后你可以通过这些步骤进行。
- 在你的仪表板上,点击应用程序。
- 单击 "创建应用程序"。
- 这个模式应该弹出,你应该选择单页网络应用。
- 然后我们可以从选项中选择Vue。
配置你的Auth0设置
现在你已经创建了应用程序,现在是时候配置设置了。
你将在基本信息部分看到你的域名和客户ID。我们稍后再来讨论这个问题;首先,我们需要将这些值存储为环境变量,以便我们的应用程序能够工作。
在应用程序的URLs部分,我们将需要定义这些值。
- 允许的回调URL
- 允许注销的URL
- 允许的网络源头
- 允许的起源(CORS)
注意,你需要使用你自己的本地URL,在本地测试你的应用程序。
允许的回调URLs
这些是你需要在用户成功登录后重定向的唯一URL。我们将使用本地的URL。
http://localhost:8080/authfinalize
我将在文章后面解释为什么我们要把用户发送到authfinalize 路径。
允许的注销URLs
这些是Auth0可以用来在你的用户注销后重定向的URL。
http://localhost:8080
允许的网络源头
这些是唯一允许向Auth0发送请求的URL。你需要添加这个URL以防止出现跨源资源共享(CORS)错误。现在,我们将添加本地的URL。
http://localhost:8080
允许的起源(CORS)
这些是唯一允许向服务器发出任何请求的URL。
http://localhost:8080
在这里,我们要设置我们的id_token 过期时间,单位是秒。我们将为这个样本网站使用36,000s(10小时)。
现在,让我们回到我们的项目文件夹,为我们的本地开发创建一个.env 文件。添加这些环境变量。
VUE_APP_AUTH0_CONFIG_RESPONSETYPE=token id_token
VUE_APP_AUTH0_CONFIG_SCOPE=openid profile email
VUE_APP_AUTH0_CONFIG_DOMAIN={{ Domain }}
VUE_APP_AUTH0_CONFIG_DOMAINURL=https://{{ Domain }}
VUE_APP_AUTH0_CONFIG_CLIENTID={{ ClientID }}
VUE_APP_DOMAINURL={{Local host URL}}
VUE_APP_DOMAINURL_REDIRECT={{ Allowed Callback URL }}
VUE_APP_EXPIRY=36000
这些变量将在我们的项目中使用,因为我们要继续下去。access token 和id_token 将在认证后作为响应返回,这可以用来验证认证用户的身份。
Domain,ClientID, 和Allowed Callback URL 都可以在设置页面找到。我们的VUE_APP_AUTH0_CONFIG_DOMAIN 和VUE_APP_AUTH0_CONFIG_DOMAINURL 的唯一区别是,我们需要在域名前面加上https:// 。Vue的所有环境变量的前缀都必须是VUE_APP 。
设置Vuex
我们将把Vuex视为我们应用程序的单一真理来源,因此它将被用来在我们的应用程序中初始化Auth0。我们还将使用它来处理我们应用程序中的数据。
首先,我们需要在我们的应用程序中导入auth0-js ,并设置我们的state 。在我们的state ,我们将初始化Auth0,并从上面讨论的环境变量中添加我们的应用程序细节。
import Vuex from "vuex";
import Vue from "vue";
import actions from "./auth/actions";
import getters from "./auth/getters";
import mutations from "./auth/mutations";
import auth0 from "auth0-js";
Vue.use(Vuex);
const state = () => ({
userIsAuthorized: false,
auth0: new auth0.WebAuth({
domain: process.env.VUE_APP_AUTH0_CONFIG_DOMAIN,
clientID: process.env.VUE_APP_AUTH0_CONFIG_CLIENTID,
redirectUri: process.env.VUE_APP_DOMAINURL_REDIRECT,
responseType: process.env.VUE_APP_AUTH0_CONFIG_RESPONSETYPE,
scope: process.env.VUE_APP_AUTH0_CONFIG_SCOPE,
}),
});
export default new Vuex.Store({
namespaced: true,
state,
actions,
getters,
mutations,
});
我们将userIsAuthorized 添加到我们的state ,以接受boolean 。我们将使用它作为一个指标来了解用户是否已经登录。注意,在应用程序的初始加载时,这将注册为假。
Vuex动作
login
用Auth0认证用户包括将用户发送到我们应用程序外的Auth0门户。之后,我们将他们返回到我们的应用程序。这个登录动作将在我们的组件中被调用以触发这个重定向。
//login.js
const login = ({state}) => {
state.auth0.authorize()
}
export default login;
//logging in within the component
<template>
<div class="home">
<button @click="login">Login</button>
<button @click="signup">Signup</button>
</div>
</template>
<script>
export default {
name: "Home",
methods: {
login() {
this.$store.dispatch('login')
},
signup() {
this.$store.dispatch('login')
}
}
};
</script>
authHandleAuthentication
当用户被送回我们的应用程序时,access token 和id_token 作为一个响应被送回给我们。这个动作设置了令牌的过期时间,然后在将用户发送到安全页面或仪表板之前,在本地存储access token 、id_token 、和过期时间。
该函数使用我们的state 内的Auth0对象的parseHash ,以检查用户是否有access token 和id_token ,然后它在将用户发送到仪表板之前将它们保存在本地。另一方面,如果有错误,用户会看到一个错误,并被重定向到主页。
//auth0HandleAuthentication.js
import router from '../../../router/index'
const auth0HandleAuthentication = (context) => {
context.state.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
let expiresAt = JSON.stringify(
(process.env.VUE_APP_EXPIRY * 1000) + new Date().getTime()
);
// save the tokens locally
localStorage.setItem("access_token", authResult.accessToken);
localStorage.setItem("id_token", authResult.idToken);
localStorage.setItem("expires_at", expiresAt);
router.push({ name : "dashboard"})
}
else if (err) {
alert("There's is an issue with signing up", err)
router.replace({ name: "home" })
}
})
};
export default auth0HandleAuthentication;
logout
我们使用logout 按钮来签出用户。它把用户带回Auth0的网站,让他们完全退出我们的应用程序。然后,它使用我们之前添加的Allowed Logout URLs ,将他们送回我们的应用程序。
//logout.js
const logout = () => {
localStorage.removeItem("access_token");
localStorage.removeItem("id_token");
localStorage.removeItem("expires_at");
window.location.href =
process.env.VUE_APP_AUTH0_CONFIG_DOMAINURL +
"/v2/logout?returnTo=" +
process.env.VUE_APP_DOMAINURL +
"/&client_id=" +
process.env.VUE_APP_AUTH0_CONFIG_CLIENTID;
};
export default logout;
//logging out on the dashboard page
<template>
<div class="hello">
<h2>Here's the dashboard</h2>
<button @click="logout">Logout</button>
</div>
</template>
<script>
export default {
name: 'Dashboard',
methods: {
logout() {
this.$store.dispatch('logout')
}
}
}
</script>
Vuex突变
我们将只有一个突变,它将被用来在我们的状态中触发我们的userIsAuthorized 指标。
const setUserIsAuthenticated = (state, replacement) => {
state.userIsAuthorized = replacement;
}
vue-router
这是行动将被触发的地方,用户将被路由,基于我们的路由守护中的某些条件。
用户流是直接的。
- 用户尝试登录
- 我们把用户送到Auth0登录门户进行认证
- 然后他们被送回我们的应用程序(特别是
/authfinalize页面),并附上access token,id_token,等等。 - 我们在本地保存这些令牌和过期时间,并将用户重定向到安全页面
在设置我们的路由时,我们将为每个路由添加meta 对象。这将使我们能够使用requiresGuest 来识别向所有人开放的路由,并使用requiresAuth 来识别受保护的路由。
这些meta 属性可以在路由位置和导航卫士上访问。
import Vue from "vue";
import VueRouter from "vue-router";
import Store from "../store"
import Home from "../views/Home.vue";
import Authfinalize from "../views/Authfinalize"
import Dashboard from "../views/Dashboard"
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: Home,
meta : {
requiresGuest : true,
}
},
{
path: "/dashboard",
name: "dashboard",
component: Dashboard,
meta : {
requiresAuth : true
}
},
{
path: "/authfinalize",
name: "Authfinalize",
component: Authfinalize,
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some((x) => x.meta.requiresAuth);
const requiresGuest = to.matched.some((x) => x.meta.requiresGuest);
const auth0callback = to.matched.some(record=>record.path == "/authfinalize");
let routerAuthCheck = false;
if(auth0callback) {
Store.dispatch('auth0HandleAuthentication');
next(false);
}
if( localStorage.getItem('access_token') && localStorage.getItem('id_token') && localStorage.getItem('expires_at') ){
let expiresAt = JSON.parse(localStorage.getItem('expires_at'));
routerAuthCheck = new Date().getTime() < expiresAt;
}
Store.commit('setUserIsAuthenticated', routerAuthCheck);
if (requiresAuth) {
if(routerAuthCheck){
next();
}
else{
Store.dispatch('logout');
}
}
if (requiresGuest && routerAuthCheck) {
next({ name: "dashboard" });
}
next();
})
export default router;
在我们的beforeEach 路由守卫中,我们应该检查预定路线有哪一个meta-object ,并相应地将其分配给requiresAuth 或requiresGuest 变量。如果我们要导航到/authfinalize 路径,我们也可以创建一个auth0callback 变量。
然后,我们创建一个名为routerAuthCheck 的变量并将其分配给false 。我们将使用这个变量来触发突变,这将改变我们之前谈到的Vuex内的指标。
第一个if block ,检查我们是否在导航到/authfinalize 路线,然后调用auth0HandleAuthentication 。请注意,我们只有在从Auth0重定向回来的时候才会导航到这条路线。
第二个if block ,检查用户是否被认证,然后它做一个commit ,当登录时,它将我们的指标切换到true ,反之亦然。基本上,它检查本地存储,看看令牌和到期日是否还在那里。
然后它进一步检查过期日期是否大于当前时间。routerAuthCheck 将反映它是true 还是false ,然后它将提交到setUserIsAuthenticated 突变,这将切换我们的应用程序指标。
第三个if block 检查预定路线是否需要认证(requiresAuth),然后检查routerAuthCheck 是true 还是false 。如果是true ,用户就会进入仪表板。如果是false ,则用户被注销。
最后一个if block ,检查已认证的用户是否正在前往主页(requiresGuest)。然后,它会自动把他们送到仪表板上。
部署你的应用程序
要部署该应用程序,你需要将你的实时URL添加到前面演示的每个设置中。用逗号把每个URL分开。
记住,你必须创建一个新的.env 文件,并在你的代码库或你要部署的平台中设置实时版本的URL,这取决于你使用什么平台进行部署。
总结
虽然有其他处理认证的方法,但像Auth0这样的工具可以给你带来时间上的优势,同时你还可以确定你的应用程序的安全性。你可以在GitHub上查看我们的代码库,并在这里找到演示网站。你也可以从Auth0的文档中了解更多。
The postHandling authentication in Vue.js using Vuex, Vue Router, and Auth0appeared first onLogRocket Blog.