zoukankan      html  css  js  c++  java
  • 聊聊常见的服务(接口)认证授权

    1597589282025

    写在前面

    头发掉得多了,总有机会接触/调到各种各样的接口,各种面向Api编程实际上已经嵌入到我们的习惯中,没办法现在服务端通信还得是http(s),其他协议还未能成为通用的。

    大厂的开发平台api我先不敢说,各种小公司、或者不少大公司内部之间,各种各样的的接口签名/授权方式可以说是尽显劳动人民智慧、八仙过海,各显神通。当然,我也曾是八仙中一员大将;

    然而,不能总当神仙,偶尔也要做下凡人。下面我们聊聊常见的服务授权方式;

    Basic Auth

    Basic Auth使用base64编码把 username:password (注意中间有个半角冒号)加密后放入请求头:

    比如账号密码 hei:123 , base64后在request--header这样:

    Authorization: Basic aGVpOjEyMw==
    

    Postman支持

    1597134736956

    总结:

    优点:简单明了,特别容易理解;

    缺点:因为简单,且几乎是明文的形式传递,总得来说不够安全;且要配合权限啊、授权策略啊要花挺多成本;

    看场景使用;

    Key Auth

    这个别看名字起得高大上,其实也就是你先定义一个 KeyName,KeyValue,调用方和接口定义方约定这个Key放在--header或者Query Params里,到时按约定好的取出就好;

    比如我定义了的

    KeyName: apikey

    KeyValue: hei.key.7LimLB5qXHtuBsI7HpxM9mj447ME3GlNoe7WxKL5

    约定好放到Header里。

    Postman支持

    1597134655775

    总结: 跟basic auth 一样,还是不够安全,虽然可以通过添加超复杂的keyValue提高安全性。但记住,只要是固定的key,永远都是不安全的。看场景使用。

    Jwt Auth

    这个知识点可是可是博客园的常客了,三天两头都有相关博文;但毕竟本片不是jwt专题,我就不长篇阔论了简单聊聊;

    首先jwt是啥

    Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519),

    传递信息的标准的说白了就是一种数据格式,它分成三个部分组成,中间用.隔开:

    img (图来自龙哥的博客

    //上图三部分一般这样组成,所以整个jwt都是base64的(除了那两个分割的'.')
    base64Url(Header)+"."+base64Url(Payload)+"."+base64Url(Signature)
    

    具体的一个jwt

    eyJhbGciOiJSUzI1NiIsImtpZCI6IjY1OTMxODE4QjYxQkIzQTVEMUIxN0Y0MEVCRTlEQkY2IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE1OTcxNDIxNzgsImV4cCI6MTU5NzE0OTM3OCwiaXNzIjoiaHR0cDovLzE3Mi4xNi4zLjExNzo1MTAwIiwiYXVkIjpbIm9jZWxvdCIsImh0dHA6Ly8xNzIuMTYuMy4xMTc6NTEwMC9yZXNvdXJjZXMiXSwiY2xpZW50X2lkIjoib2NlbG90LmNsaWVudCIsImp0aSI6IkQxRkExNkE3MkM1RDY4RDEyMTMzM0RGRjRDRDBCM0Q4IiwiaWF0IjoxNTk3MTQyMTc4LCJzY29wZSI6WyJvY2Vsb3QuYWRtaW4iXX0.PCN_Q77r0IyaesLy-Q0lTV12EYD9GkywrDMfxrCBj3ac9YltW8RzczAqdn2f92iysf_5Iu6hvTm16z9MJay6-eGWBiuIgJRXaCDlTqWWKcI8rWmW17ncyJT5oIgwip54Tfder9AfJOUJ-K0U2zT0fsrnBf7CZDLmkAAFHoxky1dzmPnh7JM4EkjtC-ybLOu_Aav7GgIOyYfodovxNgMvGHdhmheJLjxpjGblfI6o3rH8fRedwoV8zCY8MxJRGVcqg8slo0E9wfsebNx8hCV1mLHJbuDbJ1DCnDQ_1I1pFEFZCVNE2g0R-LRMC7opfFcveorNvZcJ8zEPWcACqoGXZg
    

    我们 复制到https://jwt.io/ 解析看看:

    1597142980493

    可以很清楚的看到, header部分是说明Token的类型和所使用的算法,payload部分就是授权信息,比如用户名啊、哪个服务器,什么时候发的、什么时候失效等等。signature部分是签名信息,防止篡改。

    一般是怎么用jwt的

    我借龙哥个图来说明下

    img

    1. 一般我们先定义一个颁发token服务(Auth Service --Api),服务调用方携带授权信息申请token;
    2. Auth Service验证授权信息后返回jwt;
    3. 服务调用方携带jwt请求受保护接口;
    4. 受保护接口验证jwt 的有效性,验证有没有权限、是否在有效期、有没有被篡改等(这里不用到Auth Service验,也就是去中心化的方式,这是jwt的一大有点)。这里写着是网关,其实也可以写在接口的过滤器那里,不过这样每个项目都要实现一遍验证逻辑了。
    5. 这里已经解析完jwt,打扰可以携带jwt的信息去调用接口啦;
    6. 响应,流程完;

    其实大家都差不多这么用的,不管是自定义实现还是用第三方的中间件形式,具体看需求;

    Postman支持

    1597144560719

    总结:

    优点

    • 因为json的通用性,所以JWT是可以进行跨语言支持;

    • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。

    • 便于传输,jwt的构成非常简单,传输字节不大,高性能。

    • 去中心化,高性能;

    缺点

    • 安全性:如果是完全去中心化的方式,如果jwt给黑客截取了,是没有办法吊销的,开发的时候可以考虑下如何解决这个问题;
    • 携带的信息是完全开放的,不能携带安全性高的加密信息,只能说有限安全性,依然看场景使用,不过我的经验,日常开发绝大部分时候够用了。

    Oauth2--client_credentials(客户端凭证)模式

    Oauth2.0 有多种模式,比如Authorization Code、Implicit Flow、Password Grant等、我们今天只来看client_credentials--客户端配置模式吧。

    我们先看官方的流程图

         +---------+                                  +---------------+
         |         |                                  |               |
         |         |>--(A)- Client Authentication --->| Authorization |
         | Client  |                                  |     Server    |
         |         |<--(B)---- Access Token ---------<|               |
         |         |                                  |               |
         +---------+                                  +---------------+
    

    可以看到非常简单,他其实只要:

    A、Client携带授权信息(client_id,client_scret,scopes,grant_type等)去Authorization Server 申领AccessToken;

    B、Authorization Server 颁发AccessToken;

    然后你就可以用这个AccessToken 调用 受保护的接口了;

    我们来看看实例:

    1、先请求AccessToken

    1597145029833

    2、携带AccessToken 调用受保护接口

    Postman支持

    1597145106803

    其实这里的header是这样的:

    Authorization: Bearer ZJg0rak2ZYKyZeBTH7zJzDl94AjkfwiE
    

    那可以看到我们的AccessToken ,很明显很简短,看情况是不携带任何信息的。那意味着它每次调用都需要去Authorization Server验证AccessToken 才行,这样接口调用量瞬间翻倍了,性能肯定受影响。我们能不能像上面提到的jwt一样,用jwt 做token,去中心化呢?

    答案是可以的,Oauth2.0-client_credentials模式本身是对流程的标准化,并没有限制token类型,所以我们是可以用jwt做token,但是又涉及到一个问题授权是OAth2.0的活,如果你加入jwt做身份区分那其实已经是OpenId Connect的活了,那又是另一个话题了。但那其实是一个非常好的设计,我们.net core里面就用这么个方案实现的框架IdentityServer4

    总结:identityserver4真香;

    Hmac Auth

    Hmac的全称是Hash-based Message Authentication Code(基于哈希的消息认证码), 看起来有点蒙,我们先来看个例子,比如我们有如下的接口地址:

    http://api.hei.com?userid=23233&age=18&type=normal

    我们经常会这样给我们接口加签名:

    1. 先把query参数全小写后,按a-z排序为,用&隔开:age=18&type=normal&userid=23233
    2. 对参数32位小写md5, md5_32(“age=18&type=normal&userid=23233”) 得到sign:a8b8a635cc34b95a8788abfa6f6b9ff2
    3. 把sign加在请求参数后面:http://api.hei.com?userid=23233&age=18&type=normal&sign=a8b8a635cc34b95a8788abfa6f6b9ff2
    4. 服务端按同样的方法验证参数;

    如果我们把以上的 md5_32(“排序参数”)加“盐”改为:md5_32(my_secret_key,“排序参数”) 这就是:

    Hmac-Md5 算法,同理,还有:

    Hmac-SHA1

    Hmac-SHA384

    Hmac-SHA256

    Hmac-SHA512

    等等算法,主要的区别在于哈希算法的不同。因为安全性有一定的报障,各种语言里面都会有对应的语言无关的实现,比如.net core 里面就有:HMACMD5、HMACSHA1、HMACSHA256、HMACSHA384、HMACSHA512 这五个内置类,都是调用里面的ComputeHash()。

    当然,生产中的例子可能不像上面的那么简单,比如接口调用方要求一定附加一个时间戳参数在请求里,5分钟内本请求有效,my_secret_key 非常复杂,动态 my_secret_key 等等方式。

    这个Postman当然支持:

    1597318177074

    这是我用网关kong内置的Hmac Auth 插件实现的。

    总结:

    大总结

    我觉得接口认证授权这块挺多东西,我现在用IdentityServer4+Hmac比较多,大家平时怎么处理的,也可以聊一聊~

    参考

    https://www.cnblogs.com/edisonchou/p/talk_about_what_is_jwt.html

  • 相关阅读:
    HDU 1009 FatMouse' Trade
    HDU 2602 (简单的01背包) Bone Collector
    LA 3902 Network
    HDU 4513 吉哥系列故事——完美队形II
    LA 4794 Sharing Chocolate
    POJ (Manacher) Palindrome
    HDU 3294 (Manacher) Girls' research
    HDU 3068 (Manacher) 最长回文
    Tyvj 1085 派对
    Tyvj 1030 乳草的入侵
  • 原文地址:https://www.cnblogs.com/xiaxiaolu/p/13514915.html
Copyright © 2011-2022 走看看