当前位置: 首页 > news >正文

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-plus UI包
  • @element-plus/icons-vue UI图标包
  • axios 发送请求的包
  • qs 发送请求时序列化的包
  • vue-router vue路由
  • 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. 后台配置 在本教程中&#xff0c;我将利用Visual Studio 2022的强大集成开发环境&#xff0c;结合Vue.js前端框架和ASP.NET Core后端框架&#xff0c;从头开始创建一个具备用户登录与权限验…...

【html】如何利用id选择器实现主题切换

今天给大家介绍一种方法来实现主题切换的效果 效果图&#xff1a; 源码&#xff1a; <!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 博客资源列表的全部数据。这篇文章的目标是通过模拟用户的滚动操作,加载所有的资源列表项,并提取它们的信息。 项目准备 首先,我们需要安装一些…...

智能制造全闪解决方案,八大痛点,一网打尽

当今&#xff0c;全球制造业面临多重大考验&#xff0c;如个性化需求剧增、成本上升、劳动力短缺及激烈竞争。应对这些挑战&#xff0c;智能制造成为转型关键&#xff0c;借助云技术、大数据、AI等前沿科技推动生产智能化&#xff0c;增强企业竞争力。 中国大力扶持智能制造&am…...

Python学习从0开始——Kaggle深度学习002

Python学习从0开始——Kaggle深度学习002 一、单个神经元1.深度学习2.线性单元示例 - 线性单元作为模型多个输入 3.Keras中的线性单元 二、深度神经网络1.层多种类型的层 2.激活函数3.堆叠密集层4.构建Sequential模型 三、随机梯度下降1.介绍2.损失函数3.梯度下降法1.梯度下降法…...

比利时海外媒体宣发,发稿促进媒体通稿发布新形势-大舍传媒

引言 随着全球化的推进&#xff0c;海外媒体的影响力也日益增强。在这一背景下&#xff0c;比利时海外媒体的宣发工作成为了媒体通稿发布的新形势。大舍传媒作为一家专注于宣传推广的公司&#xff0c;一直致力于与比利时博伊克邮报&#xff08;boicpost&#xff09;合作&#…...

摄影构图:人像摄影和风景摄影的一些建议

写在前面 博文内容涉及摄影中人像摄影和风景摄影的简单介绍《高品质摄影全流程解析》 读书笔记整理理解不足小伙伴帮忙指正 &#x1f603; 生活加油 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已经和从前不一样…...

安卓实现输入快递单号生成二维码,摄像头扫描快递单号生成的二维码,可以得到快递信息

背景&#xff1a; 1、实现二维码的生成和识别2、实现andriod&#xff08;或虚拟机&#xff09;部署&#xff0c;调用摄像头3、实现网络管理&#xff0c;包括数据库【取消】2、3可以组队实现&#xff0c;1必须单人实现 过程&#xff1a; 安卓APP主界面 输入快递单号信息&#…...

Mysql特殊用法分享

不存在则插入&#xff0c;存在则更新的2种写法 前置使用条件&#xff0c;必须有唯一索引 -- 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工具

大家好&#xff0c;今天给大家分享的是一个开源的快速准确地将 PDF 转换为 markdown工具。 Marker是一款功能强大的PDF转换工具&#xff0c;它能够将PDF文件快速、准确地转换为Markdown格式。这款工具特别适合处理书籍和科学论文&#xff0c;支持所有语言的转换&#xff0c;并…...

可通过小球进行旋转的十字光标(vtkResliceCursor)

前一段事件看到VTK的一个例子&#xff1a; 该案例是vtk.js写的&#xff0c;觉得很有意思&#xff0c;个人正好也要用到&#xff0c;于是萌生了用C修改VTK源码来实现该功能的想法。原本以为很简单&#xff0c;只需要修改一下vtkResliceCursor就可以了&#xff0c;加上小球&#…...

python遍历文件夹并计算某类文件的数量,制图像文件到目标文件夹

python遍历文件夹并计算某类文件的数量&#xff0c;制图像文件到目标文件夹 在Python中&#xff0c;你可以使用os和os.path模块来遍历文件夹&#xff08;目录&#xff09;。下面是一个简单的示例&#xff0c;展示了如何遍历一个文件夹中的所有文件和子文件夹&#xff1a; imp…...

网络层只懂路由?这9个知识点被严重低估了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 网络层想必你已经耳熟能详&#xff0c;它的作用自然是不容小觑。 它负责将数据从源头准确地投递到目的地&am…...

最新的kali Linux源,解决apt update报错说没有数字签名

原因&#xff1a; 国内源的地址大部分都是http开头&#xff0c;这些地址早就无法使用。 解决方案&#xff1a; wget archive.kali.org/archive-key.asc //下载签名 apt-key add archive-key.asc //安装签名 另外&#xff0c;需…...

RAG与Langchain简介

RAG与Langchain简介 什么是RAGRAG解决的问题RAG工作流程RAG调优策略LangChain简介 什么是RAG 检索增强生成&#xff08;Retrieval-Augmented Generation&#xff09;&#xff0c;主要是通过从外部给大模型补充一些知识&#xff0c;相当于给模型外挂了一个知识库&#xff0c;让…...

绕过网页的阻止复制

绕过网页的阻止复制 一、问题的提出二、绕过技巧一三、绕过技巧二四、绕过技巧三五、总结说明 一、问题的提出 也是很久没有写文章了&#xff0c;今天突发奇想写一篇文章。首先你有没有被网页中的一些阻止你复制的页面所困扰。就是那种&#xff0c;你突然找到一篇文章&#xf…...

Jackson指定json的key

指定json的key ‍ ‍ 要在序列化JavaBean时指定JSON的key&#xff0c;可以使用JsonProperty​注解来指定JavaBean属性序列化到JSON时使用的key。以下是一个简单的示例&#xff1a; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.da…...

谷歌发布Infini-Transformer模型—无限注意力机制长度,超越极限

Transformer 是一种基于自注意力机制的深度学习模型&#xff0c;最初应用于自然语言处理领域&#xff0c;现已扩展到图像、音频等多个领域。与传统的循环神经网络 (RNN) 不同&#xff0c;Transformer 不依赖于顺序数据处理&#xff0c;能够并行计算&#xff0c;从而显著提高效率…...

激光点云配准算法——Cofinet / GeoTransforme / MAC

激光点云配准算法——Cofinet / GeoTransformer / MAC GeoTransformer MAC是当前最SOTA的点云匹配算法&#xff0c;在之前我用总结过视觉特征匹配的相关算法 视觉SLAM总结——SuperPoint / SuperGlue 本篇博客对Cofinet、GeoTransformer、MAC三篇论文进行简单总结 1. Cofine…...

socket--cs--nc简单实现反弹shell

socket_client.py import socket#客户端: #连接服务段的地址和端口 #输入命令发送执行 #回显命令执行结果# ipinput(please input connect ip:) # portinput(please input connect port:)ssocket.socket() # IP and PORT s.connect((,9999)) while True:cmdlineinput(please i…...

CSS入门基础2

目录 1.标签类型 2.块元素 3.行内元素 4.行内块元素 5.标签行内转换 6.背景样式 1.标签类型 标签以什么方式进行显示&#xff0c;比如div 自己占一行&#xff0c; 比如span 一行可以放很多个HTML标签一般分为块标签和行内标签两种类型&#xff1a; 块元素行内元素。 2.块…...

Mac vscode could not import github.com/gin-gonic/gin

问题背景&#xff1a; 第一次导入一个go的项目就报红 问题分析&#xff1a; 其实就是之前没有下载和导入gin这个web框架包 gin是一个golang的微框架&#xff0c;封装比较优雅&#xff0c;API友好&#xff0c;源码注释比较明确。 问题解决&#xff1a; 依次输入以下命令。通…...

MySQL修改用户权限(宝塔)

在我们安装好的MySQL中&#xff0c;很可能对应某些操作时&#xff0c;不具备操作的权限&#xff0c;如下是解决这些问题的方法 我以宝塔创建数据库为例&#xff0c;创建完成后&#xff0c;以创建的用户名和密码登录 这里宝塔中容易发生问题的地方&#xff0c;登录不上去&#…...

论文阅读(一种新的稀疏PCA求解方式)Sparse PCA: A Geometric Approach

这是一篇来自JMLR的论文&#xff0c;论文主要关注稀疏主成分分析&#xff08;Sparse PCA&#xff09;的问题&#xff0c;提出了一种新颖的几何解法&#xff08;GeoSPCA&#xff09;。 该方法相比传统稀疏PCA的解法的优点&#xff1a;1&#xff09;更容易找到全局最优&#xff…...

Chrome/Edge浏览器视频画中画可拉动进度条插件

目录 前言 一、Separate Window 忽略插件安装&#xff0c;直接使用 注意事项 插件缺点 1 .无置顶功能 2.保留原网页&#xff0c;但会刷新原网页 3.窗口不够美观 二、弹幕画中画播放器 三、失败的尝试 三、Potplayer播放器 总结 前言 平时看一些视频的时候&#xff…...

pg修炼之道学习笔记

一、数据库逻辑结构介绍 1、一个pg数据库服务下有多个db&#xff08;多个数据库&#xff09;&#xff0c;当应用连接到一个数据库时&#xff0c;一般只能访问这个数据库中的数据&#xff0c;而不能访问其他数据库的内容&#xff08;限制&#xff09; 2、表索引&#xff1a;一…...

使用宝塔面板部署Django应用(不成功Kill Me!)

使用宝塔面板部署Django应用 文章目录 使用宝塔面板部署Django应用 本地操作宝塔面板部署可能部署失败的情况 本地操作 备份数据库 # 备份数据库 mysqldump -u root -p blog > blog.sql创建requirements # 创建requirements.txt pip freeze > requirements.txt将本项目…...

c++深拷贝、浅拷贝

在 C 中&#xff0c;深拷贝和浅拷贝是两个重要的概念&#xff0c;尤其在涉及动态内存分配和指针成员时。这两个概念描述了对象复制时的行为。 浅拷贝 浅拷贝是指复制对象时&#xff0c;仅复制对象的基本数据成员&#xff0c;对于指针成员&#xff0c;只复制指针地址&#xff…...

k8s核心组件

Master组件&#xff1a; kube-apiserver&#xff1a;用于暴露Kubernetes API&#xff0c;任何资源请求或调用操作都是通过kube-apiserver提供的接口进行。它是Kubernetes集群架构的大脑&#xff0c;负责接收所有请求&#xff0c;并根据用户的具体请求通知其他组件工作。etcd&am…...

中国英文政务网站建设/免费影视软件靠什么赚钱

文章来源: 点击打开 高斯滤波是一种线性平滑滤波&#xff0c;对于除去高斯噪声有很好的效果。在其官方文档中形容高斯滤波为”Probably the most useful filter”&#xff0c;同时也指出高斯滤波并不是效率最高的滤波算法。高斯算法在官方文档给出的解释是高斯滤波是通过对输入…...

上海热线网站建设/百度后台登录

开发过程中出现bug是很正常的事情&#xff0c;小bug无关紧要&#xff0c;可如果是重大bug该怎么办&#xff1f;一位央企程序员就陷入了这样的困境&#xff1a;因为自己没有考虑周全&#xff0c;不小心写了个重大bug&#xff0c;会造成用户个人信息泄露&#xff08;用爬虫可以攻…...

wordpress超简洁主题/跨境电商哪个平台比较好

在《【Hibernate】Hibernate的聚类查询、分组查询、排序与时间之差》&#xff08;点击打开链接&#xff09;一文中已经讲述过如何利用HQL语句取代SQL语句&#xff0c;进行聚类查询、分组查询、排序与时间之差的查询&#xff0c;同时指出hql能代替sql语句做任何事情。我原本以为…...

网站免备案空间/网络seo营销推广

1.Path注解 Path 注解可以标记在类名之上&#xff0c;也可以标记在方法名上。该注解接收一个value参数&#xff0c;表示定义资源的地址。 另外&#xff0c;资源地址相同&#xff0c;但是HTTP方法不同的两个方法是完全两个不同的REST接口&#xff0c;HTTP方法和资源地址相结合…...

一个人做网站现实吗/网络营销软件站

原文: http://coolshell.cn/articles/11564.html TCP是一个巨复杂的协议&#xff0c;因为他要解决很多问题&#xff0c;而这些问题又带出了很多子问题和阴暗面。所以学习TCP本身是个比较痛苦的过程&#xff0c;但对于学习的过程却能让人有很多收获。关于TCP这个协议的细节&…...

网站内容好/邯郸网站seo

这个问题是我刚开始接触javaEE的时候遇到的&#xff0c;虽然现在看来很简单的问题&#xff0c;但是对于初学者会很困惑&#xff0c;所以总结一下吧 当初安装tomcat的时候&#xff0c;发现有个启动tomcat服务的程序tomcat7w.exe,于是开启这个服务&#xff0c;可是当我在myeclip…...