页面.登陆
12003- 框架登陆页 loginV4.html
- 框架登陆接口 user.js
- 框架用户表 _user
在本节中,我们将介绍如何实现登陆逻辑。首先,我们将调用登陆接口 login.passwordLogin,然后在登陆成功后,使用浏览器的 cookie 和 localStorage 进行鉴权。
登陆逻辑
- 调用登陆接口
login.passwordLogin。 - 登陆成功后:
login.passwordLogin会自动给浏览器写一个 cookie,用于后续页面访问的鉴权。cookie 的 key 为${appId}_authToken,value 为 authToken。- 将接口返回的
authToken、userId和deviceId持久化到 localStorage,用于后续调用接口的鉴权。
以下是实现登陆逻辑的示例代码:
<jh-toast/><v-app><v-row class="ma-0 pa-3"><v-btn class="elevation-0 mr-2" color="success" small @click="doLogin">登陆</v-btn></v-row></v-app><script type="module">new Vue({el: '#app',template: '#app-template',vuetify: new Vuetify(),data: {userId: 'test',password: '123456',deviceId: 'test_001',},methods: {async doLogin() {window.vtoast.loading("登陆");const resultData = (await window.jianghuAxios({data: {appData: {pageId: 'login',actionId: 'passwordLogin',actionData: {userId: this.userId,password: this.password,deviceId: this.deviceId},}}})).data.appData.resultData;const { authToken, userId, deviceId } = resultData;localStorage.setItem(`${window.appInfo.authTokenKey}_authToken`, authToken);localStorage.setItem(`${window.appInfo.authTokenKey}_userId`, userId);localStorage.setItem(`${window.appInfo.authTokenKey}_deviceId`, deviceId);window.vtoast.success("登陆");},}})</script>
使用 authToken
- 当用户访问页面时,cookie 会自动传输到服务器。
- 当用户调用接口时,将 authToken 放入请求体的 data 中。若使用 jianghuAxios 发起接口请求,jianghuAxios 会自动从 localStorage 取 authToken 填入请求体的 data 中。
await window.jianghuAxios({data: {authToken: 'xxxxx',appData: {pageId: 'test',actionId: 'selectItemList',actionData: {},}}})
现在,我们已经成功实现了登陆逻辑,并使用 cookie 和 localStorage 进行鉴权。这使得我们可以在用户访问页面和调用接口时进行有效的身份验证。
完整的登陆案例
<jh-toast /><jh-mask /><jh-confirm-dialog /><v-app><v-main><v-row class="align-center" style="height: 100vh"><v-col cols="12" align="center"><div class="mb-10 text-h7 font-weight-bold success--text"><$ ctx.app.config.appTitle $></div><v-card class="login-form-card pa-8"><v-card-text class="pa-0"><div class="title">登录您的账户</div><v-form ref="loginForm" lazy-validation><!-- 表单 [注:登录表单包含密码输入框,chrome密码自动填充的时候会与vuetify的v-input组件样式冲突,使用原生input避免冲突] --><v-row class="my-0"><v-col cols="12"><input class="jh-cus-input" v-model="userId" placeholder="用户名" /></v-col><v-col cols="12"><div class="password-wrapper"><input class="jh-cus-input" v-model="password":type="isPasswordShown ? 'text' : 'password'" data-type="password"@keyup.enter.exact="doUiAction('login')" placeholder="密码" /><v-icon @click="isPasswordShown = !isPasswordShown" smallclass="mdi-eye">{{isPasswordShown ? 'mdi-eye-off-outline' :'mdi-eye-outline'}}</v-icon></div></v-col></v-row><!-- 操作按钮 --><v-row class="my-0 px-3"><v-btn block color="success" @click="doUiAction('login')" small>登录</v-btn></v-row></v-form></v-card-text></v-card></v-col></v-row></v-main></v-app>{% include 'utility/jianghuJs/prepareDeviceIdV4.html' %}<script type="module">new Vue({el: '#app',template: '#app-template',vuetify: new Vuetify(),data: {userId: '',password: '',deviceId: null,isPasswordShown: false,},async created() {},async mounted() {},methods: {async doUiAction(uiActionId, uiActionData) {try {switch (uiActionId) {case 'login':await this.prepareLoginData();await this.doLogin();await this.setLocalStorage();await this.redirectToPreLoginURL();break;default:console.error("[doUiAction] uiActionId not found", { uiActionId });break;}} catch (error) {throw error;} finally {window.jhMask && window.jhMask.hide();}},// ---------- login uiAction >>>>>>>>>> --------async prepareLoginData() {this.deviceId = window.deviceId;this.userId = _.replace(this.userId, /\s+/g, '');;this.password = _.toString(this.password);},async doLogin() {try {const resultData = (await window.jianghuAxios({data: {appData: {pageId: 'login',actionId: 'passwordLogin',actionData: {userId: this.userId,password: this.password,deviceId: this.deviceId},}}})).data.appData.resultData;this.loginResult = resultData;window.vtoast.success('登录成功');} catch (error) {const { errorCode, errorReason } = error || {};if (errorCode) {window.vtoast.fail(errorReason);throw new Error("登录失败", { errorCode, errorReason });} else {window.vtoast.fail('登录失败');throw new Error("登录失败");}}},async setLocalStorage() {localStorage.setItem(`${window.appInfo.authTokenKey}_authToken`, this.loginResult.authToken);localStorage.setItem(`${window.appInfo.authTokenKey}_userId`, this.loginResult.userId);localStorage.setItem(`${window.appInfo.authTokenKey}_deviceId`, this.deviceId);},async redirectToPreLoginURL() {// 重定向到帮助页// window.location.href =`/${window.appInfo.appId}/page/help`;}// ---------- <<<<<<<<<<< login uiAction --------}})</script><style scoped>.login-form-card {width: 400px;}/* ---------- 输入框 >>>>>>>>>> -------- */.jh-cus-input {border: 1px solid rgba(0, 0, 0, .06);width: 100%;height: 32px;border-radius: 6px;padding: 0 12px;color: #5E6278 !important;outline: none;font-size: 13px !important;}.jh-cus-input:focus,.jh-cus-input:focus-visible,input:focus-visible {border: thin solid #4caf50 !important;}/* ---------- <<<<<<<<<<< 输入框 -------- *//* ---------- 密码框 >>>>>>>>>> -------- */.password-wrapper {position: relative;}.password-wrapper .mdi-eye {position: absolute;right: 8px;top: 8px;}/* ---------- <<<<<<<<<<< 密码框 -------- */</style>