学习设计微服务:api认证
前言
最近再学习微服务,所以把自己的个人站点https://www.ttblog.site/拆分成微服务。目前正在思考微服务里面的认证与授权,网上百度到都是根据用户名和密码来实现的,考虑到实际的原因,我的个人站点是最先访问不需要登录,当执行写入或更改操作时才需要用户名和密码,所以我自己思考了一个方案,这里分享一下,设计难免有很多不合理之处,大家可以予以批评。
文档
我开始做的时候,对认证授权不是很理解,所以我在网上百度并且在博客园和开源中国提了一下问。https://www.oschina.net/question/2859520_2319077和https://q.cnblogs.com/q/129422/。并且看了很多文章,大多数使用的是IdentityServer4,但是我发现这个比较复杂,貌似还要安装一些认证,所以选择了使用JWT。并且了解了一下OAuth2,我觉得我用的应该属于里面的客户端模式https://www.jianshu.com/p/84a4b4a1e833。大概都了解之后,我就开始在项目里集成了jwt和ocelot。
实战
首先创建了一个认证服务器
BlogAuthApi
然后一个网关
BlogGateway
最后一个
BlogWebApi
我的思路就是js判断是否存有token,如果没有在请求认证服务器Auth,,返回一个token,存入浏览器,然后之后通过token去访问webapi。
1,请求token
我这里使用的微服务网关属于Ocelot,请求时通过网关转发到认证服务器获取token,如下代码生成token:
public class Jwt
{
/// <summary>
/// 返回jwt模型
/// </summary>
/// <returns></returns>
public static JwtOption GetOption()
{
JwtOption option = ConfigureProvider.BuildModel<JwtOption>("jwtOption");
return option;
}
/// <summary>
/// 返回SymmetricSecurityKey
/// </summary>
/// <returns></returns>
public static SymmetricSecurityKey GetSymmetricSecurityKey()
{
JwtOption option = GetOption();
return GetSymmetricSecurityKey(option.Secret);
}
/// <summary>
/// 返回SymmetricSecurityKey
/// </summary>
/// <returns></returns>
public static SymmetricSecurityKey GetSymmetricSecurityKey(string secret)
{
return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
}
/// <summary>
/// 返回token参数模型
/// </summary>
/// <returns></returns>
public static TokenValidationParameters GetTokenValidation()
{
JwtOption option = GetOption();
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = GetSymmetricSecurityKey(option.Secret),
ValidateIssuer = true,
ValidIssuer = option.Issuer,
ValidateAudience = true,
ValidAudience = option.Audience,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
RequireExpirationTime = true, };
return tokenValidationParameters;
}
/// <summary>
/// 获取jwt的token参数
/// </summary>
/// <param name="claims"></param>
/// <returns></returns>
public static JwtSecurityToken GetJwtParameters(Claim[] claims,JwtOption option=null)
{
if (option == null)
option = GetOption();
var jwt = new JwtSecurityToken(
issuer: option.Issuer,
audience: option.Audience,
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.Add(TimeSpan.FromMinutes(option.ExpireMinutes)),
signingCredentials: new SigningCredentials(GetSymmetricSecurityKey(option.Secret), SecurityAlgorithms.HmacSha256)
);
return jwt;
}
/// <summary>
/// 获取jwt
/// </summary>
/// <param name="claims"></param>
/// <returns></returns>
public static JwtToken GetToken(JwtSecurityToken tokenParameters)
{
JwtOption option = GetOption();
string token=new JwtSecurityTokenHandler().WriteToken(tokenParameters);
return new JwtToken(token, option.ExpireMinutes);
}
/// <summary>
/// 获取jwt
/// </summary>
/// <param name="claims"></param>
/// <returns></returns>
public static JwtToken GetToken(Claim[] claims)
{
JwtOption option = GetOption();
JwtSecurityToken jwtSecurityToken = GetJwtParameters(claims,option);
string token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
return new JwtToken(token, option.ExpireMinutes*60);
}
} public class JwtToken
{
public string Token { get; set; }
public int ExpireSeconds { get; set; }
public JwtToken(string token,int expireSeconds)
{
Token = token;
ExpireSeconds = expireSeconds;
}
}
public class JwtOption
{
public string Issuer { get; set; }
public string Audience { get; set; }
public int ExpireMinutes { get; set; }
public string Secret { get; set; }
}
 并且添加配置文件
 "jwtOption": {
    "issuer": "",
    "audience": "",
    "expireMinutes": "",
    "secret": ""
  }然后前端获取到token之后会吧token放入到header里面请求。
2,配置网关服务Ocelot
使用ocelot认证时,需要配置Ocelot.json,对相应的路由添加节点
 {
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5001
        }
      ],
      "UpstreamPathTemplate": "/{url}",
      "UpstreamHttpMethod": [ "Get", "Post", "Delete" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "ApiAuthKey",//认证服务的key
        "AllowedScopes": []
      },
      //限流
      "RateLimitOptions": {
        "ClientWhitelist": [],
        "EnableRateLimiting": true,
        "Period": "1s",
        "PeriodTimespan": 1,
        "Limit": 1
      }
    }
让后需要在Startup里面添加Jwt如下:
services.AddAuthentication()
.AddJwtBearer("ApiAuthKey", x =>
{
x.RequireHttpsMetadata = false;
x.TokenValidationParameters = tokenValidationParameters;
});
之后启动3个服务来测试下,
当我们不传token时,请求时直接返回401的:
然后我们请求认证服务器获取token
然后我们把token放入header里面请求:
可以看到请求成功了,并且我们可以看到token的过期时间为120秒,然后过了两分钟我们在请求就不行了
到此,我的api认证功能已经大致完成了,因为自己并没有这方面的经验,例如怎么token过期了前端怎么取刷新的问题,怎么扩展ocelot过期返回的response等等,自己都是要一点一点去学习了解的,这里只是贴出我的过程,和大家分享讨论下,希望可以给出好的意见。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2020/09/30 16:43
这里作为后续的更新,
之前我已经讲过如何认证token,然后我下午又想了一个刷新token的方法,讲一下我的思路。
首先是认证服务器返回token,过期时间,token创建时间3个字段,然后前端存储这3个字段。
例如当一次请求的时候token为空,则请求token并存储,第二次请求时如果token有值,则根据过期时间,token创建时间来判断是否过期没如果过期了就在此请求token,并且更新当前的localStorge,代码如下
/**
* 字符串转日期
*/
function stringToDate(str){
var tempStrs = str.split(" ");
var dateStrs = tempStrs[0].split("-");
var year = parseInt(dateStrs[0], 10);
var month = parseInt(dateStrs[1], 10) - 1;
var day = parseInt(dateStrs[2], 10);
var timeStrs = tempStrs[1].split(":");
var hour = parseInt(timeStrs [0], 10);
var minute = parseInt(timeStrs[1], 10);
var second = parseInt(timeStrs[2], 10);
var date = new Date(year, month, day, hour, minute, second);
return date;
}
/**
* 全局ajax处理
*/
layui.use('layer', function () {
var layer = layui.layer;
$.ajaxSetup({
cache: false,
beforeSend: function (xhr) {
var token = localStorage.getItem('token');//token
var tokenExpireTime = localStorage.getItem('tokenExpireTime');//过期时间
var tokenSaveTime = localStorage.getItem('tokenSaveTime');//token保存时间
var requestToken = false;//是否需要获取token
if (token == undefined || tokenExpireTime == undefined || tokenSaveTime == null) {
requestToken = true;
}
if (!requestToken) {//不需要时判断token是否过期
if (tokenExpireTime == undefined) {
requestToken = true;
}
else {
var now = new Date();
tokenSaveTime = stringToDate(tokenSaveTime);
var s=now.getTime()-tokenSaveTime.getTime();
//计算出相差天数
var days=Math.floor(s/(24*3600*1000))
//计算出小时数
var leave1=s%(24*3600*1000) //计算天数后剩余的毫秒数
var hours=Math.floor(leave1/(3600*1000))
//计算相差分钟数
var leave2=leave1%(3600*1000) //计算小时数后剩余的毫秒数
var minutes=Math.floor(leave2/(60*1000))
//计算相差秒数
//var leave3=leave2%(60*1000) //计算分钟数后剩余的毫秒数
//var seconds=Math.round(leave3/1000)
if(days>0)
{
requestToken = true
}
else if(hours>0){
requestToken = true
}
else if(minutes>tokenExpireTime){
requestToken = true
}
}
}
if (requestToken) {
$.ajax({
url: api + '/auth/token',
type: 'get',
datatype: 'json',
async:false,
beforeSend: function () {
var i=1;防止调用token时会通过ajaxStup再次执行beforeSend
},
success: function (res) {
if (res.code == 200) {
token=res.data.token;
localStorage.setItem('token', res.data.token);
localStorage.setItem('tokenExpireTime', res.data.expireMinutes);
localStorage.setItem('tokenSaveTime', res.data.createTime);
}
},
complete: function () {
var i=1;
}
})
}
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
},
error: function (request) {
layer.msg('响应服务器失败', {
icon: 7
});
},
});
})
学习设计微服务:api认证的更多相关文章
- 微服务中台落地  中台误区  当中台遇上DDD,我们该如何设计微服务
		小结: 1. 微服务中台不是 /1堆砌技术组件就是中台 /2拥有服务治理就是中台 /3增加部分业务功能就是中台 /4Cloud Native 就是中台 https://mp.weixin.qq.com ... 
- 【Spring Cloud & Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权
		一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证授权.鉴权的逻辑,结合 ... 
- .NET Core 微服务—API网关(Ocelot) 教程 [三]
		前言: 前一篇文章<.NET Core 微服务—API网关(Ocelot) 教程 [二]>已经让Ocelot和目录api(Api.Catalog).订单api(Api.Ordering)通 ... 
- 【微服务】之六:轻松搞定SpringCloud微服务-API网关zuul
		通过前面几篇文章的介绍,我们可以轻松搭建起来微服务体系中比较重要的几个基础构建服务.那么,在本篇博文中,我们重点讲解一下,如何将所有微服务的API同意对外暴露,这个就设计API网关的概念. 本系列教程 ... 
- Java面试必会-微服务权限认证
		微服务身份认证方案 1. 单点登录(SSO) 这种方案意味着每个面向用户的服务都必须与认证服务交互,这会产生大量非常琐碎的网络流量和重复的工作,当动辄数十个微应用时,这种方案的弊端会更加明显. 2. ... 
- 微服务API Gateway
		翻译-微服务API Gateway 原文地址:http://microservices.io/patterns/apigateway.html,以下是使用google翻译对原文的翻译. 让我们想象一下 ... 
- .NET Core 微服务—API网关(Ocelot) 教程 [二]
		上篇文章(.NET Core 微服务—API网关(Ocelot) 教程 [一])介绍了Ocelot 的相关介绍. 接下来就一起来看如何使用,让它运行起来. 环境准备 为了验证Ocelot 网关效果,我 ... 
- 当中台遇上DDD,我们该如何设计微服务? - InfoQ https://www.infoq.cn/article/7QgXyp4Jh3-5Pk6LydWw
		当中台遇上DDD,我们该如何设计微服务? - InfoQ https://www.infoq.cn/article/7QgXyp4Jh3-5Pk6LydWw 
- 对微服务API服务网关的理解
		目录微服务专栏地址目录1. 简介2. 什么是API网关3. 为什么需要API网关4. API网关在微服务架构体系中处于什么位置4.1 调用者眼中的API网关4.2 所处的位置5. 网关技术实现有哪些6 ... 
- 【微服务】之七:轻松搞定SpringCloud微服务-API权限控制
		权限控制,是一个系统当中必须的重要功能.张三只能访问输入张三的特定功能,李四不能访问属于赵六的特定菜单.这就要求对整个体系做一个完善的权限控制体系.该体系应该具备针区分用户.权限.角色等各种必须的功能 ... 
随机推荐
- ZYNQ:PetaLinux工程更新HDF文件的脚本
			PetaLinux工程更新HDF文件的脚本 参考:PetaLinux工程更新HDF文件的脚本 工程师可能同时使用多个Vivado工程,以便测试不同的硬件配置.如果能够让一个PetaLinux工程支持多 ... 
- QT学习:03 信号与槽
			--- title: framework-cpp-qt-03-信号与槽 EntryName: framework-cpp-qt-03-signal-slot date: 2020-04-09 13:5 ... 
- 记一次 .NET某网络边缘计算系统 卡死分析
			一:背景 1. 讲故事 早就听说过有什么 网络边缘计算,这次还真给遇到了,有点意思,问了下 chatgpt 这是干嘛的 ? 网络边缘计算是一种计算模型,它将计算能力和数据存储位置从传统的集中式数据中心 ... 
- 从PDF到OFD,国产化浪潮下多种文档格式导出的完美解决方案
			前言 近年来,中国在信息技术领域持续追求自主创新和供应链安全,伴随信创上升为国家战略,一些行业也开始明确要求文件导出的格式必须为 OFD 格式.OFD 格式目前在政府.金融.税务.教育.医疗等需要文件 ... 
- 好消息!数据库管理神器 Navicat 推出免费精简版:Navicat Premium Lite
			前言 好消息,前不久Navicat推出了免费精简版的数据库管理工具Navicat Premium Lite,可用于商业和非商业目的,我们再也不需要付费.找破解版或者找其他免费平替工具了,有需要的同学可 ... 
- MySQL 索引失效
			全列匹配 最佳左前缀法则 不在索引列上做任何操作(计算.函数.自动.手动类型转换),会导致索引失效 存储引擎不能使用索引中范围条件右边的列 尽量使用覆盖索引(只访问索引的查询(索引和查询列一致)),少 ... 
- 基于 Impala 的高性能数仓建设实践之虚拟数仓
			导读:本文主要介绍网易数帆 NDH 在 Impala 上实现的虚拟数仓特性,包括资源分组.水平扩展.混合分组和分时复用等功能,可以灵活配置集群资源.均衡节点负载.提高查询并发,并充分利用节点资源. 接 ... 
- PositiveSmallIntegerField、SmallIntegerField和IntegerField
			当您在Django中定义模型时,有几种不同的整数字段类型可供选择,包括PositiveSmallIntegerField.SmallIntegerField和IntegerField.以下是这三种整数 ... 
- 图的存储、创建、遍历、求最小生成树、最短路径(Java)
			带权无向图 存储结构 存储结构选用邻接表. 当一个图为稀疏图时,使用邻接矩阵法显然要浪费大量的存储空间,而图的邻接表法结合了顺序存储和链式存储方法,大大减少了这种不必要的浪费. 当然,即使我们所处理的 ... 
- JAVA并发编程理论基础
			注:本文章是对极客时间<java并发编程实战>学习归纳总结,更多知识点可到原文 java并发编程实战 进行学习.如果侵权,联系删除: 一.并发编程的BUG的源头 1.1 缓存导致的可见性问 ... 
