在前后端分离的项目中,首先我们要解决的问题就是身份认证

以往的时候,我们使用cookie+session,或者只用cookie来保持会话。

一,先来复习一下cookie和session

首先我们来复习一下在aspnet中cookie和session的关系,做一个简单试验

这是一个普通的view没有任何处理

可以看到,没有任何东西(cookie),然后当我们写入一个session之后

\

会发现多了一个名为ASP.NET_SessionId的cookie。我们都知道在aspnet中,session是保存在服务器端的内存中的,而http协议是无状态的,那么他是怎么确定不同请求的session

没错,session是借助cookie来实现的:cookie中保存着 session的key,当我们清除掉浏览器缓存时,会发现session也找不到了,就是这个原因。

使用session来保持会话有几个很严重的缺点:1 session容易丢失;2无法支持分布式;3,cookie 对跨域的支持不好

所以就用到了我们今天说的token

二,token 

1,token的产生

一般是用户登录成功,服务器端产生一个token并返给前端,前端将token保存在cookie或者localStorage里面,然后每次请求时都带上这个token,一般都带在请求头里面

 2,token的内容

一般的token里面必须有的是:1,会话用户的标识:比如userid。2,token的过期时间,如果想更完整一点,可以加上token的颁发者,签名等等

3,token的生成算法,一般是由服务器端将token的主要内容,过期时间等等做非对称加密,然后进行签名算法(防止客户端更改),具体看后面jwt

4,token校验

当服务器端收到请求时,首先会校验token,校验有两种不同的方式

 一, token产生后保存在服务器端(redis或者其他比较速度快的缓存中) 。优点:可控性强,可以用这个来做单点登录,比如另一个地方登录,就remove掉之前的token。缺点:实现麻烦一点,而且要占服务器压力

二, token产生后服务器端不保存,只负责校验。 优点:大大降低了服务器的压力,实现起来,也要相对简单一点。缺点:token一旦颁发,服务器端就不可控了,只能等它过期。

    具体用哪种看具体的需求。如果不是做可控性要求很强,个人建议第二种。

5 jwt 

jwt 全名Json Web Tokens,算是一种token的规范吧

园子里面有很不不错的介绍 ,比如这篇:阮一峰 jwt介绍   http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

 

组成有三部分

  • Header(头部,一般包含了token的签名方式)
  • Payload(负载,也就是具体的有效部分)
  • Signature(签名,将前两部分进行签名算法,防止客户端篡改)

实现方式,将header部分和payload部分分别进行base64算法,然后用点号“.”隔开拼接,然后进行签名算法,然后在将三部分拼接(点号隔开)就得到了jwt

注意 ,jwt默认是采用base64编码的,也就是说 客户端也能解码得出具体内容的,所以除非特殊情况,重要敏感字段一定不能放在token中

以下是具体实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web; namespace Rk.JWT
{ public class Jwt
{ //参考自 阮一峰 jwt介绍 http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html public static string SALT = "OXpcRP8jmCfMKumY"; /// <summary>
///
/// </summary>
/// <param name="ExraPayload">额外的信息</param>
/// <returns></returns>
public static string Create(Dictionary<string,object> ExraPayload)
{
var Header = new Dictionary<string, string>();
Header.Add("tp", "MD5");
var Payload = new Dictionary<string, object>(); //JWT 规定了7个官方字段,供选用。
Payload.Add("iss", "signBy"); //颁发人
Payload.Add("jti", Guid.NewGuid().ToString()); //jwt的id
Payload.Add("exp",System.DateTime.Now.AddMinutes(20));//过期时间
Payload.Add("nbf", System.DateTime.Now);//生效时间
Payload.Add("iat", System.DateTime.Now);//签发时间
Payload.Add("sub", "subject");//主题
Payload.Add("aud", "audience");//受众 foreach (var item in ExraPayload)
{
if (Payload.ContainsKey(item.Key))
{ throw new Exception($"{item.Key}键值已被占用 不能使用 ");
}
else
{
Payload.Add(item.Key, item.Value);
}
}
string base64Header = Base64Url(Newtonsoft.Json.JsonConvert.SerializeObject(Header));
string base64Payload = Base64Url(Newtonsoft.Json.JsonConvert.SerializeObject(Payload));
string tmp = base64Header + "." + base64Payload; string sign = Md5(tmp+ SALT);//加盐,重要 return base64Header+"."+ base64Payload+"."+ sign;
} //校验是否合法,是否过期
public static bool Check(string token)
{
string base64Header = token.Split('.')[0];
string base64Payload = token.Split('.')[1];
string sign = token.Split('.')[2];
string tmp = base64Header + "." + base64Payload;
var signCheck = Md5(base64Header + "." + base64Payload + SALT);
if(signCheck!= sign)
{
return false;
}
var dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlDecode(base64Payload));
if( Convert.ToDateTime(dic["exp"])<System.DateTime.Now)
{
//过期了
return false; }
return true; }
//校验是否合法,是否过期
public static Dictionary<string,object> GetPayLoad(string token)
{ string base64Payload = token.Split('.')[1]; var dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlDecode(base64Payload)); return dic; } public static string Base64Url(string input)
{
//JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。
//Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。
string output = "";
byte[] bytes = Encoding.UTF8.GetBytes(input);
try
{
output = Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').TrimEnd('=') ; }
catch (Exception e)
{
throw e;
}
return output;
}
public static string Base64UrlDecode(string input)
{
string output = ""; input = input.Replace('-', '+').Replace('_', '/');
switch (input.Length % 4)
{
case 2:
input += "==";
break;
case 3:
input += "=";
break;
}
byte[] bytes = Convert.FromBase64String(input);
try
{
output = Encoding.UTF8.GetString(bytes);
}
catch
{
output = input;
}
return output;
}
public static string Md5(string input,int bit=16)
{ MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
byte[] hashedDataBytes;
hashedDataBytes = md5Hasher.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(input));
StringBuilder tmp = new StringBuilder();
foreach (byte i in hashedDataBytes)
{
tmp.Append(i.ToString("x2"));
}
if (bit == 16)
return tmp.ToString().Substring(8, 16);
else
if (bit == 32) return tmp.ToString();//默认情况
else return string.Empty; }
} }

  

  使用方式

 public class HomeController : BaseController
{ public ActionResult Login(string username, string pwd)
{ /// 1, todo 验证用户名密码正确 //2,//在token中加入用户id,创建token
var dic = new Dictionary<string, object>();
dic.Add("userid", "20125521225858");
string token = JWT.Jwt.Create(dic); //验证token是否正确是否过期
var isChecked = JWT.Jwt.Check(token); return Content(""); }
}

  

下一篇我们将会聊一聊 rest 风格url在前后端分离项目中的使用

Aspnet Mvc 前后端分离项目手记(二)关于token认证的更多相关文章

  1. Aspnet Mvc 前后端分离项目手记(三)关于restful 风格Url设计

    RESTful 不是新东西,简单理解它的核心思想就是最大程度的利用http协议的一些特点,比如uri,比如请求动词,在前后端分离的项目中会有大大的好处 ,好的设计的url简单明了,胜过详细的说明文档. ...

  2. Aspnet Mvc 前后端分离项目手记(一) 关于跨域问题(还有前言)

    前言,最近的项目使用前后端分离的模式,记录其中一些知识点.经过这个项目,也对前后端分离有了更多理解,尤其是在技术之外的方面. 越来越多的项目采用前后端分离的原因,有两点:      1,技术方面的原因 ...

  3. Aspnet Mvc 前后端分离项目手记(四)vue项目的搭建(一)(iview)

    一项目创建 1,搭建vue-cli脚手架(依赖npm) 没有安装npm的同学,请先使用npm install -g vue-cli ,然后再进行这一步 安装的过程中有几项 ? Project name ...

  4. 从零开始搭建django前后端分离项目 系列二(项目搭建)

    在开始项目之前,假设你已了解以下知识:webpack配置.vue.js.django.这里不会教你webpack的基本配置.热更新是什么,也不会告诉你如何开始一个django项目,有需求的请百度,相关 ...

  5. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  6. Yii框架和Vue的完美结合完成前后端分离项目

    背景说明 本文假设你对Yii和Vue都比较熟悉,至少都在项目里用过,另外笔者新人,以后不定时放一些干货,欢迎程序媛关注 Yii是一个PHP全端框架,典型的mvc的项目结构,后端接口都是一个控制器里放了 ...

  7. 基于Vue的前后端分离项目实践

    一.为什么需要前后端分离 1.1什么是前后端分离  前后端分离这个词刚在毕业(15年)那会就听说过,但是直到17年前都没有接触过前后端分离的项目.怎么理解前后端分离?直观的感觉就是前后端分开去做,即功 ...

  8. docker-compose 部署 Vue+SpringBoot 前后端分离项目

    一.前言 本文将通过docker-compose来部署前端Vue项目到Nginx中,和运行后端SpringBoot项目 服务器基本环境: CentOS7.3 Dokcer MySQL 二.docker ...

  9. 如何使用Spring Securiry实现前后端分离项目的登录功能

    如果不是前后端分离项目,使用SpringSecurity做登录功能会很省心,只要简单的几项配置,便可以轻松完成登录成功失败的处理,当访问需要认证的页面时,可以自动重定向到登录页面.但是前后端分离的项目 ...

随机推荐

  1. Java线程池源码解析

    线程池 假如没有线程池,当存在较多的并发任务的时候,每执行一次任务,系统就要创建一个线程,任务完成后进行销毁,一旦并发任务过多,频繁的创建和销毁线程将会大大降低系统的效率.线程池能够对线程进行统一的分 ...

  2. java接口多实现和多继承

    package test; interface mouth { public abstract void speak(); } interface nose{ public abstract void ...

  3. 第31月第25天 xcode debug 限制uitextfiled输入

    1.xcode debug 了解了每个设置的意思,个人觉得对于一个普通的app来说可以这样配置这些设置: Generate Debug Symbols:DEBUG和RELEASE下均设为YES(和Xc ...

  4. Oracle 里 case 和decode的简单用法

    case 就相想当于C#里面switch    l 列:根据员工的职位,计算加薪后的薪水数据 如果职位是Analyst , 加薪10% 如果职位是Programmer 加薪5% 如果职位是clerk ...

  5. mysql命令行的导入导出sql,txt,excel(都在linux或windows命令行操作)(转自筑梦悠然)

    原文链接https://blog.csdn.net/wuhuagu_wuhuaguo/article/details/73805962 Mysql导入导出sql,txt,excel 首先我们通过命令行 ...

  6. html-webpack-plugin详解

    引言 我们来看看主要作用: 为html文件中引入的外部资源如script.link动态添加每次compile后的hash,防止引用缓存的外部文件问题 可以生成创建html入口文件,比如单页面可以生成一 ...

  7. springboot格式化时间

    使用@RestController注解,返回的java对象中若含有date类型的属性,则默认输出为TIMESTAMP时间戳格式,可以在配置文件加入下面配置 spring.jackson.date-fo ...

  8. Bootstrap常用表单布局

    参考链接: https://blog.csdn.net/shuai_wy/article/details/78978023

  9. python制作串口工具

    # coding:utf-8import timeimport serialimport stringimport binasciiimport linecache FilePath="G: ...

  10. 结合jira搭建自动化测试平台

    mysql 语句查看 python manage.py sqlmigrate your_app_name 0001 代码如下 #coding=utf8 #https://jira.readthedoc ...