个人网站设计主题,免费写作文网站,漳州市城乡住房建设局网站,哈尔滨公告点击上方蓝字小黑在哪里关注我吧登录菜单权限运行测试前言上一篇已经创建好了前后端项目#xff0c;本篇开始编码部分。开始几乎所有的系统都绕不开登录功能#xff0c;那么就从登录开始#xff0c;完成用户登录以及用户菜单权限控制。登录首先用户输入账号密码… 点击上方蓝字小黑在哪里关注我吧登录菜单权限运行测试前言上一篇已经创建好了前后端项目本篇开始编码部分。开始几乎所有的系统都绕不开登录功能那么就从登录开始完成用户登录以及用户菜单权限控制。登录首先用户输入账号密码点击登录然后组合以下参数调用identityserver的/connect/token端点获取token{grant_type: password,scope: HelloAbp,username: ,password: ,client_id: HelloAbp_App,client_secret: 1q2w3e*
}
这个参数来自ABP模板的种子数据我使用的是password flow这个flow无需重定向。如果你的网站应用只有一个的话可以这么做如果有多个的话建议采用其他oidc方式把认证界面放到identityserver程序里客户端重定向到identityserver去认证这样其实更安全并且你无需在每个客户端网站都做一遍登录界面和逻辑。。。还有一点严格来说不应该直接访问/connect/token端点获取token。首先应该从identityserver发现文档/.well-known/openid-configuration中获取配置信息然后从/.well-known/openid-configuration/jwks端点获取公钥等信息用于校验token合法性最后才是获取token。ABP的Angular版本就是这么做的不过他是使用angular-oauth2-oidc这个库完成我暂时没有找到其他的支持password flow的开源库参考https://github.com/IdentityModel/oidc-client-js/issues/234前端想正常访问接口首先需要在HttpApi.HostIdentityServer增加跨域配置前端部分需要修改的文件太多下面只贴出部分主要代码需要完整源码的可以去GitHub拉取。src\store\modules\user.jsconst clientSetting {grant_type: password,scope: HelloAbp,username: ,password: ,client_id: HelloAbp_App,client_secret: 1q2w3e*
};
const actions {// user loginlogin({ commit }, userInfo) {const { username, password } userInforeturn new Promise((resolve, reject) {clientSetting.username username.trim()clientSetting.password passwordlogin(clientSetting).then(response {const data responsecommit(SET_TOKEN, data.access_token)setToken(data.access_token).then(() {resolve()})}).catch(error {reject(error)})})},// get user infogetInfo({ commit }) {return new Promise((resolve, reject) {getInfo().then(response {const data responseif (!data) {reject(Verification failed, please Login again.)}const { name } datacommit(SET_NAME, name)commit(SET_AVATAR, )commit(SET_INTRODUCTION, )resolve(data)}).catch(error {reject(error)})})},setRoles({ commit }, roles) {commit(SET_ROLES, roles)},// user logoutlogout({ commit, dispatch }) {return new Promise((resolve, reject) {logout().then(() {commit(SET_TOKEN, )commit(SET_NAME, )commit(SET_AVATAR, )commit(SET_INTRODUCTION, )commit(SET_ROLES, [])removeToken().then(() {resetRouter()// reset visited views and cached views// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485dispatch(tagsView/delAllViews, null, { root: true })resolve()})}).catch(error {reject(error)})})},// remove tokenresetToken({ commit }) {return new Promise(resolve {commit(SET_TOKEN, )commit(SET_NAME, )commit(SET_AVATAR, )commit(SET_INTRODUCTION, )commit(SET_ROLES, [])removeToken().then(() {resolve()})})}
}
src\utils\auth.jsexport async function setToken(token) {const result Cookies.set(TokenKey, token);await store.dispatch(app/applicationConfiguration);return result;
}export async function removeToken() {const result Cookies.remove(TokenKey);await store.dispatch(app/applicationConfiguration);return result;
}
src\api\user.jsexport function login(data) {return request({baseURL: https://localhost:44364,url: /connect/token,method: post,headers: { content-type: application/x-www-form-urlencoded },data: qs.stringify(data),});
}export function getInfo() {return request({url: /api/identity/my-profile,method: get,});
}export function logout() {return request({baseURL: https://localhost:44364,url: /api/account/logout,method: get,});
}
src\utils\request.jsservice.interceptors.request.use((config) {// do something before request is sentif (store.getters.token) {config.headers[authorization] Bearer getToken();}return config;},(error) {// do something with request errorconsole.log(error); // for debugreturn Promise.reject(error);}
);// response interceptor
service.interceptors.response.use((response) {const res response.data;return res;},(error) {console.log(err error); // for debugMessage({message: error.message,type: error,duration: 5 * 1000,});if (error.status 401) {// to re-loginMessageBox.confirm(You have been logged out, you can cancel to stay on this page, or log in again,Confirm logout,{confirmButtonText: Re-Login,cancelButtonText: Cancel,type: warning,}).then(() {store.dispatch(user/resetToken).then(() {location.reload();});});}return Promise.reject(error);}
);
菜单权限vue-element-admin的菜单权限是使用用户角色来控制的我们不需要role。前面分析过通过/api/abp/application-configuration接口的auth.grantedPolicies字段与对应的菜单路由绑定就可以实现权限控制了。src\permission.jsrouter.beforeEach(async (to, from, next) {// start progress barNProgress.start();// set page titledocument.title getPageTitle(to.meta.title);let abpConfig store.getters.abpConfig;if (!abpConfig) {abpConfig await store.dispatch(app/applicationConfiguration);}if (abpConfig.currentUser.isAuthenticated) {if (to.path /login) {// if is logged in, redirect to the home pagenext({ path: / });NProgress.done(); // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939} else {//user nameconst name store.getters.name;if (name) {next();} else {try {// get user infoawait store.dispatch(user/getInfo);store.dispatch(user/setRoles, abpConfig.currentUser.roles);const grantedPolicies abpConfig.auth.grantedPolicies;// generate accessible routes map based on grantedPoliciesconst accessRoutes await store.dispatch(permission/generateRoutes,grantedPolicies);// dynamically add accessible routesrouter.addRoutes(accessRoutes);// hack method to ensure that addRoutes is complete// set the replace: true, so the navigation will not leave a history recordnext({ ...to, replace: true });} catch (error) {// remove token and go to login page to re-loginawait store.dispatch(user/resetToken);Message.error(error || Has Error);next(/login?redirect${to.path});NProgress.done();}}}} else {if (whiteList.indexOf(to.path) ! -1) {// in the free login whitelist, go directlynext();} else {// other pages that do not have permission to access are redirected to the login page.next(/login?redirect${to.path});NProgress.done();}}
});
src\store\modules\permission.jsfunction hasPermission(grantedPolicies, route) {if (route.meta route.meta.policy) {const policy route.meta.policy;return grantedPolicies[policy];} else {return true;}
}export function filterAsyncRoutes(routes, grantedPolicies) {const res [];routes.forEach((route) {const tmp { ...route };if (hasPermission(grantedPolicies, tmp)) {if (tmp.children) {tmp.children filterAsyncRoutes(tmp.children, grantedPolicies);}res.push(tmp);}});return res;
}const state {routes: [],addRoutes: [],
};const mutations {SET_ROUTES: (state, routes) {state.addRoutes routes;state.routes constantRoutes.concat(routes);},
};const actions {generateRoutes({ commit }, grantedPolicies) {return new Promise((resolve) {let accessedRoutes filterAsyncRoutes(asyncRoutes, grantedPolicies);commit(SET_ROUTES, accessedRoutes);resolve(accessedRoutes);});},
};
src\router\index.jsexport const asyncRoutes [{path: /permission,component: Layout,redirect: /permission/page,alwaysShow: true, // will always show the root menuname: Permission,meta: {title: permission,icon: lock,policy: AbpIdentity.Roles},children: [{path: page,component: () import(/views/permission/page),name: PagePermission,meta: {title: pagePermission,policy: AbpIdentity.Roles}},{path: directive,component: () import(/views/permission/directive),name: DirectivePermission,meta: {title: directivePermission,policy: AbpIdentity.Roles}},{path: role,component: () import(/views/permission/role),name: RolePermission,meta: {title: rolePermission,policy: AbpIdentity.Roles}}]},。。。。。。// 404 page must be placed at the end !!!{ path: *, redirect: /404, hidden: true }
]
因为菜单太多了就拿其中的一个“权限测试页”菜单举例将它与AbpIdentity.Roles绑定测试。运行测试运行前后端项目使用默认账号admin/1q2w3E*登录系统正常的话就可以进入这个界面了目前可以看到“权限测试页”菜单因为现在还没有设置权限的界面所以我手动去数据库把这条权限数据删除然后测试一下但是手动去数据库改这个表的话会有很长一段时间的缓存在redis中暂时没去研究这个缓存机制正常通过接口修改应该不会这样。。。我手动清理了redis运行结果如下最后本篇实现了前端部分的登录和菜单权限控制但是还有很多细节问题需要处理。比如右上角的用户头像ABP的默认用户表中是没有头像和用户介绍字段的下篇将完善这些问题还有删除掉vue-element-admin多余的菜单。如果本文对您有用不妨点个“在看”或者转发朋友圈支持一下