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…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
