Vue.js结合ASP.NET Core构建用户登录与权限验证系统
- 1. 环境准备
- 2. 创建项目
- 3. Vue配置
- 步骤一: 安装包
- 步骤二: 配置文件
- 步骤三: 页面文件
- 4. 后台配置
在本教程中,我将利用Visual Studio 2022的强大集成开发环境,结合Vue.js前端框架和ASP.NET Core后端框架,从头开始创建一个具备用户登录与权限验证功能的Web应用程序。我们将充分利用Visual Studio的内置工具和模板来简化开发流程。
1. 环境准备
Visual Studio 2022,Vue3
2. 创建项目
打开Visual Studio 2022,选择“创建新项目”。在项目模板搜索框中输入“Vue and ASP.NET Core”,选择模板后点击“下一步”。
按照图中配置:

生成目录如下:

3. Vue配置
步骤一: 安装包
右键npm->安装新的npm包
element-plusUI包@element-plus/icons-vueUI图标包axios发送请求的包qs发送请求时序列化的包vue-routervue路由jwt-decode令牌解码
步骤二: 配置文件
-
封装
axios
新建axios.js文件,内容如下:// axios.jsimport axios from 'axios'; import PLATFROM_CONFIG from '../public/config';const instance = axios.create({baseURL: PLATFROM_CONFIG.baseURL, // 替换为实际的 API 地址timeout: 10000, });instance.defaults.headers.post['Content-Type'] = 'application/json';// 添加请求拦截器 axios.interceptors.request.use((config) => {// 在发送请求之前做些什么return config; }, function (error) {// 对请求错误做些什么return Promise.reject(error); });// 添加响应拦截器 axios.interceptors.response.use(function (response) {// 对响应数据做点什么if (response.status === 200) {return Promise.resolve(response);} else {return Promise.reject(response);} }, function (error) {// 对响应错误做点什么return Promise.reject(error); });export const get = (url, params) => {return instance.get(url, { params }); };export const post = (url, data) => {// data = QS.stringify(data);return instance.post(url, data); }; -
创建路由
新建router文件夹,并新建router.js文件
import { createRouter, createWebHashHistory } from 'vue-router'import qs from 'qs';
import { ElMessage } from 'element-plus'import { post } from '../axios';import Home from '../components/Home.vue'
import Setting from '../components/Setting.vue'
import Login from '../components/Login.vue'
import LoginOut from '../components/LoginOut.vue'// 路由配置
const routes = [{ path: '/', component: Home },{ path: '/Login', component: Login },{ path: '/Setting', component: Setting, meta: { requiresAuth: true, role: 'ShortcutManage;' } },{ path: '/LoginOut', component: LoginOut },
]const router = createRouter({history: createWebHashHistory(),routes,
})
// 路由守卫,在这里创建验证的流程
router.beforeEach((to, from, next) => {const accessToken = localStorage.getItem('accessToken');if (to.meta.requiresAuth && !accessToken) {// 如果需要认证并且没有令牌,则重定向到登录页next('/Login');} else {if (to.meta.requiresAuth) {// 如果有令牌判断令牌是否过期//判断令牌是否过期const decodedToken = jwtDecode(accessToken);const expirationTime = decodedToken.exp * 1000;const isTokenExpired = expirationTime < Date.now();// 已经过期if (isTokenExpired) {next('/LoginOut');} else { // 没有过期// 判断是否需要指定权限if (typeof (to.meta.role) !== 'undefined' && to.meta.role != null) {let USER_INFO = qs.parse(localStorage.getItem("userInfo"))post("Login/ValidPerm", { username: USER_INFO.ad, userPowr: to.meta.role }).then(res => {next();}).catch(err => {console.log(err)ElMessage({message: '您没有权限,请联系管理员!',type: 'warning',})})} else {next();}}} else {next();}}
});export default router
- 配置
main.js
import './assets/main.css'import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage} from 'element-plus'
import 'element-plus/dist/index.css'
import router from './router/router'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { get, post } from './axios';
import App from './App.vue'
import * as utils from './utils';
import qs from 'qs'import ELHeader from './components/custom/ElHeader.vue'
import ElAside from './components/custom/ElAside.vue'const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component)
}Object.entries(utils).forEach(([key, value]) => {app.config.globalProperties[`$${key}`] = value;
});app.config.globalProperties.$get = get;
app.config.globalProperties.$qs = qs;
app.config.globalProperties.$post = post;
app.config.globalProperties.$message = ElMessage;app.config.globalProperties.$USER_INFO = qs.parse(localStorage.getItem("userInfo"))app.use(ElementPlus)
app.use(router)app.component('ELHeader', ELHeader).component('ELAside',ElAside); app.mount('#app')
步骤三: 页面文件
- 登陆页面
Login.vue
<template><el-form :model="loginForm" ref="loginForm" :inline="false" size="large"><el-form-item prop="Username" :rules="{required: true,message: 'Username can not be null',trigger: 'blur',
}"><el-input v-model="loginForm.Username" placeholder="Okta Account"><template #prepend><el-icon><User /></el-icon></template></el-input></el-form-item><el-form-item prop="Password" :rules="{required: true,message: 'Password can not be null',trigger: 'blur',
}"><el-input type="password" v-model="loginForm.Password" placeholder="Okta Password"><template #prepend><el-icon><Lock /></el-icon></template></el-input></el-form-item><el-form-item><el-button class="login-btn" type="primary" @click="loginOn">登陆</el-button></el-form-item></el-form>
</template>
<script lang="js">
import { defineComponent } from 'vue';
export default defineComponent({data() {return {loginForm: {Username: '',Password: '',auth: "ShortcutLinks"}}},methods: {loginOn() {this.$refs.loginForm.validate((valid) => {if (valid) {let that = thisthis.$post("/Login/LoginVerify", this.loginForm).then(res => {if (res.data.success) {// 检测是否有TokenlocalStorage.setItem('accessToken', res.data.data.token)let userInfo = res.data.datauserInfo.token = nulllocalStorage.setItem('userInfo', this.$qs.stringify(userInfo))that.$router.push('/')} else {this.$message({showClose: true,message: res.data.message,type: 'warning',})}}).catch(err => {console.error(err)})} else {console.log('error submit!')return false}})}},mounted(){this.Yaer = new Date().getFullYear()}
})
</script>
- 注销界面
LoginOut.vue
<template><div>退出登陆成功!</div>
</template><script lang="js">
import { defineComponent } from 'vue';export default defineComponent({data() {return {}}, mounted() {localStorage.removeItem('userInfo');localStorage.removeItem('accessToken'); this.$router.push('/Login');}
})
</script>
- 修改App.vue
<template><router-view></router-view>
</template><style scoped></style>
4. 后台配置
创建一个生成Token的工具类TokenService
public class TokenService{private readonly string _secretKey;private readonly string _issuer;private readonly string _audience;public TokenService(string secretKey, string issuer, string audience){_secretKey = secretKey;_issuer = issuer;_audience = audience;}public string GenerateToken(string username){var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);var claims = new[]{new Claim(ClaimTypes.Name, username),// Add additional claims as needed};var token = new JwtSecurityToken(_issuer,_audience,claims,expires: DateTime.Now.AddMonths(1), // Token expiration timesigningCredentials: credentials);return new JwtSecurityTokenHandler().WriteToken(token);}}
配置跨域Program.cs`
在Buidl()之前增加:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";builder.Services.AddCors(options =>
{options.AddPolicy(name: MyAllowSpecificOrigins, policy =>{policy.WithOrigins("*").AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();});
});
登陆验证
LoginController.cs
[HttpPost("LoginVerify")]public async Task<Result<LoginInfo>> LoginVerify([FromBody] LoginModel loginModel){if (string.IsNullOrEmpty(loginModel.Username) || string.IsNullOrEmpty(loginModel.Password)){return Result<LoginInfo>.Fail("用户名或密码不能为空!");}if (string.IsNullOrEmpty(loginModel.Auth) || !"ShortcutLinks".Equals(loginModel.Auth)){return Result<LoginInfo>.Fail("令牌识别错误!");}string responseContent = await IsValidUser(loginModel.Username, loginModel.Password);if ("Unauthorized".Equals(responseContent)){return Result<LoginInfo>.Fail("验证失败!");}if ("The user name or password is incorrect.".Equals(responseContent)){return Result<LoginInfo>.Fail("用户名或密码错误!");}try{// 加密秘钥,可以自定义string key = "Ns9XoAdW7Pb3Cv9Fm2Zq4t6w8y/B?E(H+MbQeThWmZq4t7w9z$C&F)J@NcRfUjXn2r5u8x/A%D*G-KaPdSgVkYp3s6v9y";// 我自己的登陆验证方法,根据实际情况可以修改LoginInfo loginInfo = JsonConvert.DeserializeObject<LoginInfo>(responseContent);// 生成验证的Tokenvar tokenService = new TokenService(key, "ShortcutLinksServer", "ShortcutLinksClient");// 为Token添加一个标识,我这里使用的用户的ADvar token = tokenService.GenerateToken(loginInfo.AD);loginInfo.token = token;// 生成的信息返回前天return Result<LoginInfo>.Suc(loginInfo);}catch (Exception){return Result<LoginInfo>.Fail("登陆失败!");}}相关文章:
Vue.js结合ASP.NET Core构建用户登录与权限验证系统
1. 环境准备2. 创建项目3. Vue配置步骤一: 安装包步骤二: 配置文件步骤三: 页面文件 4. 后台配置 在本教程中,我将利用Visual Studio 2022的强大集成开发环境,结合Vue.js前端框架和ASP.NET Core后端框架,从头开始创建一个具备用户登录与权限验…...
【html】如何利用id选择器实现主题切换
今天给大家介绍一种方法来实现主题切换的效果 效果图: 源码: <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initia…...
服务器添加TLS域名证书核子之PKCS编解码
PKCS PKCS(Public Key Cryptography Standards)是一系列的标准,用于定义在公钥密码体系中涉及的一些基本结构和算法。PKCS#1 和 PKCS#8 是两个不同的标准,分别定义了不同的公钥私钥编码和封装格式。 PKCS#1 和PKCS#8区别 PKCS#1 PKCS#1 定义了一种用于RSA算法的公钥和私…...
使用 Selenium 自动化获取 CSDN 博客资源列表
使用 Selenium 自动化获取 CSDN 博客资源列表 在这篇博客中,我将向大家展示如何使用 Selenium 自动化工具来滚动并获取 CSDN 博客资源列表的全部数据。这篇文章的目标是通过模拟用户的滚动操作,加载所有的资源列表项,并提取它们的信息。 项目准备 首先,我们需要安装一些…...
智能制造全闪解决方案,八大痛点,一网打尽
当今,全球制造业面临多重大考验,如个性化需求剧增、成本上升、劳动力短缺及激烈竞争。应对这些挑战,智能制造成为转型关键,借助云技术、大数据、AI等前沿科技推动生产智能化,增强企业竞争力。 中国大力扶持智能制造&am…...
Python学习从0开始——Kaggle深度学习002
Python学习从0开始——Kaggle深度学习002 一、单个神经元1.深度学习2.线性单元示例 - 线性单元作为模型多个输入 3.Keras中的线性单元 二、深度神经网络1.层多种类型的层 2.激活函数3.堆叠密集层4.构建Sequential模型 三、随机梯度下降1.介绍2.损失函数3.梯度下降法1.梯度下降法…...
比利时海外媒体宣发,发稿促进媒体通稿发布新形势-大舍传媒
引言 随着全球化的推进,海外媒体的影响力也日益增强。在这一背景下,比利时海外媒体的宣发工作成为了媒体通稿发布的新形势。大舍传媒作为一家专注于宣传推广的公司,一直致力于与比利时博伊克邮报(boicpost)合作&#…...
摄影构图:人像摄影和风景摄影的一些建议
写在前面 博文内容涉及摄影中人像摄影和风景摄影的简单介绍《高品质摄影全流程解析》 读书笔记整理理解不足小伙伴帮忙指正 😃 生活加油 不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样…...
安卓实现输入快递单号生成二维码,摄像头扫描快递单号生成的二维码,可以得到快递信息
背景: 1、实现二维码的生成和识别2、实现andriod(或虚拟机)部署,调用摄像头3、实现网络管理,包括数据库【取消】2、3可以组队实现,1必须单人实现 过程: 安卓APP主界面 输入快递单号信息&#…...
Mysql特殊用法分享
不存在则插入,存在则更新的2种写法 前置使用条件,必须有唯一索引 -- 1 REPLACE INTO REPLACE INTO typora.ip_view_times_record (ip, view_times, url) VALUES(10.25.130.64, 1, https://10.25.168.80/fhh/index.html?urlindex.md543);-- 2 ON DUPLI…...
一个开源的快速准确地将 PDF 转换为 markdown工具
大家好,今天给大家分享的是一个开源的快速准确地将 PDF 转换为 markdown工具。 Marker是一款功能强大的PDF转换工具,它能够将PDF文件快速、准确地转换为Markdown格式。这款工具特别适合处理书籍和科学论文,支持所有语言的转换,并…...
可通过小球进行旋转的十字光标(vtkResliceCursor)
前一段事件看到VTK的一个例子: 该案例是vtk.js写的,觉得很有意思,个人正好也要用到,于是萌生了用C修改VTK源码来实现该功能的想法。原本以为很简单,只需要修改一下vtkResliceCursor就可以了,加上小球&#…...
python遍历文件夹并计算某类文件的数量,制图像文件到目标文件夹
python遍历文件夹并计算某类文件的数量,制图像文件到目标文件夹 在Python中,你可以使用os和os.path模块来遍历文件夹(目录)。下面是一个简单的示例,展示了如何遍历一个文件夹中的所有文件和子文件夹: imp…...
网络层只懂路由?这9个知识点被严重低估了
号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部 下午好,我的网工朋友。 网络层想必你已经耳熟能详,它的作用自然是不容小觑。 它负责将数据从源头准确地投递到目的地&am…...
最新的kali Linux源,解决apt update报错说没有数字签名
原因: 国内源的地址大部分都是http开头,这些地址早就无法使用。 解决方案: wget archive.kali.org/archive-key.asc //下载签名 apt-key add archive-key.asc //安装签名 另外,需…...
RAG与Langchain简介
RAG与Langchain简介 什么是RAGRAG解决的问题RAG工作流程RAG调优策略LangChain简介 什么是RAG 检索增强生成(Retrieval-Augmented Generation),主要是通过从外部给大模型补充一些知识,相当于给模型外挂了一个知识库,让…...
绕过网页的阻止复制
绕过网页的阻止复制 一、问题的提出二、绕过技巧一三、绕过技巧二四、绕过技巧三五、总结说明 一、问题的提出 也是很久没有写文章了,今天突发奇想写一篇文章。首先你有没有被网页中的一些阻止你复制的页面所困扰。就是那种,你突然找到一篇文章…...
Jackson指定json的key
指定json的key 要在序列化JavaBean时指定JSON的key,可以使用JsonProperty注解来指定JavaBean属性序列化到JSON时使用的key。以下是一个简单的示例: import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.da…...
谷歌发布Infini-Transformer模型—无限注意力机制长度,超越极限
Transformer 是一种基于自注意力机制的深度学习模型,最初应用于自然语言处理领域,现已扩展到图像、音频等多个领域。与传统的循环神经网络 (RNN) 不同,Transformer 不依赖于顺序数据处理,能够并行计算,从而显著提高效率…...
激光点云配准算法——Cofinet / GeoTransforme / MAC
激光点云配准算法——Cofinet / GeoTransformer / MAC GeoTransformer MAC是当前最SOTA的点云匹配算法,在之前我用总结过视觉特征匹配的相关算法 视觉SLAM总结——SuperPoint / SuperGlue 本篇博客对Cofinet、GeoTransformer、MAC三篇论文进行简单总结 1. Cofine…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
