在打代码之前先说一下思路。

登录的的时候服务端生成加密的字符串(用户名、id、当前时间)并且存入客户端cookie中,服务端的缓存中。对客户端的每次请求进行拦截,解密保存在cookie中的加密字符串。查看是否已过期,如果已过期跳转到登录页,并且删除cookie与缓存中的数据。如未过期修改缓存中的时间,并进行下一步操作。

加密解密的代码

引入包:Microsoft.Extensions.Configuration(读配置文件的时候会用到,加密key与解密key最好存在配置文件中,从配置文件中读取)

    public class Encryption
{
private IConfiguration _configuration;
public Encryption(IConfiguration configuration)
{
_configuration = configuration;
} public byte[] EncrKey()
{
return ASCIIEncoding.ASCII.GetBytes(_configuration["MD5:EncrKey"]);
}
public byte[] DecrKey()
{
return ASCIIEncoding.ASCII.GetBytes(_configuration["MD5:DecrKey"]);
} /// <summary>
/// DES加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public async Task<string> Encrypt(string str)
{
MemoryStream ms = null;
CryptoStream cs = null;
StreamWriter sw = null; DESCryptoServiceProvider des = new DESCryptoServiceProvider();
try
{
var s= ASCIIEncoding.ASCII.GetBytes(_configuration["MD5:EncrKey"]);
ms = new MemoryStream();
cs = new CryptoStream(ms, des.CreateEncryptor(this.EncrKey(), this.DecrKey()), CryptoStreamMode.Write);
sw = new StreamWriter(cs);
sw.Write(str);
sw.Flush();
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.GetBuffer(), , (int)ms.Length);
}
finally
{
if (sw != null) sw.Close();
if (cs != null) cs.Close();
if (ms != null) ms.Close();
}
} /// <summary>
/// DES解密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public async Task<string> Decrypt(string str)
{
MemoryStream ms = null;
CryptoStream cs = null;
StreamReader sr = null; DESCryptoServiceProvider des = new DESCryptoServiceProvider();
try
{
ms = new MemoryStream(Convert.FromBase64String(str));
cs = new CryptoStream(ms, des.CreateDecryptor(this.EncrKey(), this.DecrKey()), CryptoStreamMode.Read);
sr = new StreamReader(cs);
return sr.ReadToEnd();
}
finally
{
if (sr != null) sr.Close();
if (cs != null) cs.Close();
if (ms != null) ms.Close();
}
}
}

操作Redis

引入包:StackExchange.Redis

连接字符串最好也存入配置文件中

  public class RedisContent
{
public StackExchange.Redis.ConnectionMultiplexer Redis = null;
public StackExchange.Redis.IDatabase db = null; public RedisContent(IConfiguration configuration)
{
_configuration = configuration;
this.Redis = ConnectionMultiplexer.Connect($"{_configuration["Redis:dbconn"]}");
this.db = this.Redis.GetDatabase();
}
private IConfiguration _configuration;
}

定义一个特性类,对于一些不需要认证的接口,加上这个特性即可。相当于微软的[AllowAnonymous]认证中间件。这里的话我们自己写一个。

 public class AllowAuthAttribute : Attribute
{
}

添加过滤器AuthorizeFilter。上面封装的一些方法,全部以注入的形式进行使用。

    public class AuthorizeFilter : Attribute, IAuthorizationFilter
{
private readonly ILogger<AuthorizeFilter> _logger;
private readonly RedisContent _content;
private readonly Encryption _encryption;
public AuthorizeFilter(RedisContent content,
Encryption encryption,
ILogger<AuthorizeFilter> logger)
{
_content = content;
_encryption = encryption;
_logger = logger;
} public void OnAuthorization(AuthorizationFilterContext context)
{
var isDefined = false;
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
//判断请求的控制器和方法有没有加上AllowAuthAttribute(不需要认证)
isDefined = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
.Any(a => a.GetType().Equals(typeof(AllowAuthAttribute)));
}
if (isDefined) return;
if (context.HttpContext.Request.Path == "/")
return;
string value = string.Empty;
context.HttpContext.Request.Cookies.TryGetValue("userinfo", out value);
if (string.IsNullOrEmpty(value))
context.HttpContext.Response.Redirect("https://localhost:44300/");
else
{
//解密cookie
var decryptValueArray = _encryption.Decrypt(value).Result.Split("|");
string user = _content.db.StringGet($"{decryptValueArray[0]}-{decryptValueArray[2]}");
if (string.IsNullOrEmpty(user) || !user.Equals(value))
{
_logger.LogError($"Token已过期/有误! Url:{context.HttpContext.Request.Path}");
context.HttpContext.Response.Cookies.Delete("userinfo");
context.HttpContext.Response.Redirect("https://localhost:44300/");
}
else
{
//重新设置key的时间
_content.db.KeyExpire($"{decryptValueArray[0]}-{decryptValueArray[2]}", TimeSpan.FromMinutes());
return;
}
}
}
}

编写控制器中的代码

        /// <summary>
/// 验证登录 颁发Token 存入cookie
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns></returns>
[AllowAuth]
public async Task<IActionResult> LoginUser(string userName, string password)
{
if (string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(password))
return Json(new { success = false, msg = "用户名或密码不能为空" });
//带参查询
var data = await _userInfoServices.QueryUserInfo(userName, password);
if (data.Any())
{
//得到uid,将uid也带进token中加密
var uid = data.ToList()[].id;
//加密 30分钟的有效期
var token = await _encryption.Encrypt(userName + "|" + DateTime.Now + "|" + uid + "|" + );
//存入redis中
_content.db.StringSet($"{userName}" + "-" + uid, token, TimeSpan.FromMinutes());
//存入cookie中
Response.Cookies.Append("userinfo", token);
return Json(new { success = true, msg = "登陆成功" });
}
else
{
return Json(new { success = false, msg = "用户名或密码输入错误" });
}
}

如有不足,还望见谅!

.Net Core MVC 基于Cookie进行用户认证的更多相关文章

  1. Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录

    1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...

  2. 理解ASP.NET Core - 基于Cookie的身份认证(Authentication)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 概述 通常,身份认证(Authentication)和授权(Authorization)都会放 ...

  3. Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证

    在JavaScript前端技术大行其道的今天,我们通常只需在后台构建API提供给前端调用,并且后端仅仅设计为给前端移动App调用.用户认证是Web应用的重要组成部分,基于API的用户认证有两个最佳解决 ...

  4. JWT 实现基于API的用户认证

    基于 JWT-Auth 实现 API 验证 如果想要了解其生成Token的算法原理,请自行查阅相关资料 需要提及的几点: 使用session存在的问题: session和cookie是为了解决http ...

  5. 5分钟搞懂:基于token的用户认证

    https://www.qikegu.com/easy-understanding/880 用户认证 用户认证或者说用户登录是确认某人确实是某人的过程,生活中靠身份证,网络上就要靠账号和密码.用户提供 ...

  6. 项目一:第十一天 2、运单waybill快速录入 3、权限demo演示-了解 5、权限模块数据模型 6、基于shiro实现用户认证-登录(重点)

    1. easyui DataGrid行编辑功能 2. 运单waybill快速录入 3. 权限demo演示-了解 4. Apache shiro安全框架概述 5. 权限模块数据模型 6. 基于shiro ...

  7. Linux下基于LDAP统一用户认证的研究

    Linux下基于LDAP统一用户认证的研究                   本文出自 "李晨光原创技术博客" 博客,谢绝转载!

  8. 基于cookie的用户登录状态管理

    cookie是什么 先来花5分钟看完这篇文章:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies 看完上文,相信大家对cookie已经有 ...

  9. net core体系-web应用程序-4asp.net core2.0 项目实战(1)-12基于cookie登录授权认证并实现前台会员、后台管理员同时登录

    1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...

随机推荐

  1. 关于Quartz .NET(V3.0.7)的简要说明

    目录 0. 任务调度 1. Quartz .NET 1.1 基本概念 1.2 主要接口和对象 2. 使用示例 2.0 准备工作 2.1 每间隔一定时间间隔执行一次任务 2.3 某天的固定时间点执行任务 ...

  2. Spring Boot 整合 Redis 和 JavaMailSender 实现邮箱注册功能

    Spring Boot 整合 Redis 和 JavaMailSender 实现邮箱注册功能 开篇 现在的网站基本都有邮件注册功能,毕竟可以通过邮件定期的给用户发送一些 垃圾邮件 精选推荐

  3. python基本数据类型及其使用方法

    前言 ​ python中的数据类型主要为int.float.string.list.tuple.dict.set.bool.bytes.接下来int和float统称为数字类型. 1.数据类型总结 按存 ...

  4. VirtualBox 版本 6.1.2 r135662, ubuntu18 配置共享文件夹、openssh-server

    续上章安装完ubuntu18. 输入账号密码,登录成功. 但是使用ssh工具,却登录失败. 1.安装openssh-server sudo apt install openssh-server 2.检 ...

  5. OpenCV-Python 直方图-2:直方图均衡 | 二十七

    目标 在本节中, 我们将学习直方图均衡化的概念,并利用它来提高图像的对比度. 理论 考虑这样一个图像,它的像素值仅局限于某个特定的值范围.例如,较亮的图像将把所有像素限制在高值上.但是一幅好的图像会有 ...

  6. Homebrew中国镜像安装与配置

    1.删除旧Homebrew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/u ...

  7. coding++:java-Date日期转换工具类

    Code: package com.tree.ztree_demo.utils; import org.springframework.util.ObjectUtils; import java.te ...

  8. 武林高手?敏捷开发,唯velocity取胜

    去年学习软件工程教材,初识敏捷开发.目前所在的团队,也是使用敏捷开发方式.今天读了这篇文章,对于这段时间的效率有所警醒.其次,个人认同文章中的用户故事,结对编程思想. 文章援引:http://gitb ...

  9. C++ 趣图

    一.心形 1. http://mathworld.wolfram.com/HeartCurve.html #include<stdio.h> using namespace std; in ...

  10. 经验总结:超详细的 Linux C/C++ 学习路线!大厂面试指南

    ❝ 文章每周持续更新,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) ❞ 最近在知乎经常被邀请回答类似如何学习C++和C++后台开 ...