欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

IdentityServer4笔记整理(更新中)

程序员文章站 2022-09-27 19:32:02
"1 OAuth 2.0" "1.1 OAuth 2.0协议流程图" "1.2 授权码模式" "1.3 简化模式" "2 OpenID Connect(OIDC)" "2.1 OIDC协议流程图" "2.2 OIDC在OAuth 2.0之上的扩展内容" "3 JSON Web Token" "3.1 ......

博客与笔记无法实时同步, 笔记最新链接

oauth 2.0

定义:oauth 2.0是一个开放授权标准:允许资源所有者(用户)授权第三方应用访问该用户在某服务上的特定私有资源,但不提供账号密码给第三方应用。
安全提示:授权码和所有令牌必须通过tsl加密传输。进入oauth 2.0官网

oauth 2.0协议流程图

     +--------+                               +---------------+
     |        |--(a)- authorization request ->|   resource    |
     |        |                               |     owner     |
     |        || authorization |
     | client |                               |     server    |
     |        ||    resource   |
     |        |                               |     server    |
     |        |

授权码模式

授权码模式:code的生命周期必须短暂、或者只能单次使用,如果code被多次使用,授权服务器必须使该code生成的所有令牌失效。访问令牌由client后端保存。

     +----------+
     | resource |
     |   owner  |
     |          |
     +----------+
          ^
          |
         (b)
     +----|-----+          client identifier      +---------------+
     |         -+----(a)-- & redirection uri ---->|               |
     |  user-   |                                 | authorization |
     |  agent  -+----(b)-- user authenticates --->|     server    |
     |          |                                 |               |
     |         -+----(c)-- authorization code ------(d)-- authorization code ---------'      |
     |  client |          & redirection uri                  |
     |         |                                             |
     |         |

简化模式

要点:不支持刷新令牌,访问令牌编码在url中,所以会有暴露的风险(在oauth2.0官网中已经不推荐使用)

     +----------+
     | resource |
     |  owner   |
     |          |
     +----------+
          ^
          |
         (b)
     +----|-----+          client identifier     +---------------+
     |         -+----(a)-- & redirection uri --->|               |
     |  user-   |                                | authorization |
     |  agent  -|----(b)-- user authenticates -->|     server    |
     |          |                                |               |
     |          ||   web-hosted  |
     |          |          without fragment      |     client    |
     |          |                                |    resource   |
     |     (f)  |

openid connect(oidc)

定义:它在oauth2上构建了一个身份层,是一个基于oauth2协议的身份认证标准协议

IdentityServer4笔记整理(更新中)

oidc协议流程图

+--------+                                   +--------+
|        |                                   |        |
|        |---------(1) authn request-------->|        |
|        |                                   |        |
|        |  +--------+                       |        |
|        |  |        |                       |        |
|        |  |  end-  ||        |
|        |  |  user  |                       |        |
|   rp   |  |        |                       |   op   |
|        |  +--------+                       |        |
|        |                                   |        |
|        ||        |
|        |                                   |        |
|        |

oidc在oauth之上的扩展

  • [ ] scope:openid(用来区分这是一个oidc的authentication请求,而不是oauth2的authorization请求)
  • [ ] response_type:id_token,在implicit模式下请求id_token
  • [ ] id_token:身份令牌,是一个授权服务器提供的包含用户信息(由一组cliams构成以及其他辅助的cliams)的jwt格式的数据结构
  • [ ] userinfo endpoint:通过id_token从用户信息终结点获得一组eu相关的claims,比如可以将claims从token移除,避免token过大,只保留sub,通过userinfo endpoint查询claims
"response_type"参数值 oidc授权类型
code authorization code flow
id_token token implicit flow
code id_token hybrid flow
  • authorization code flow:从授权终结点返回code,从令牌终结点返回token
  • implicit flow:从授权终结点返回所有token
  • hybrid flow:id_token返回给前端,access_token在后端保存(access_token的安全性要求比id_token)高

json web token

定义:jwt是一个定义一种紧凑的,自包含的并且提供防篡改机制的传递数据的方式的标准协议

jwt格式

jwt由3部分构成:header.payload.signature
在idsrv中,payload中的键值对根据token类型和授权流程的不同有所区别
header:
{
  "alg": "rs256",//签名算法
  "kid": "9dcf733a1192a6da053e64c6ee22ff87",
  "typ": "jwt"//token类型
}
payload://需要传递的数据
{
  "nbf": 1556591630,//该jwt在此之前无效
  "exp": 1556595230,//该jwt在此之后无效
  "iss": "http://localhost:7102",//jwt颁发者
  "iat": 1516239022,//jwt颁发时间
  "aud": "http://localhost:7102/resources",//jwt接收者
  "client_id": "jsimplicit",
  "sub": "subjectid",//用户唯一id
  "auth_time": 1556591629,//授权时间
  "idp": "local",//identityprovider
  "name": "username",
  "scope": [
    "openid",
    "profile"
  ],
  "amr": [
    "pwd"//authenticationmethod
  ]
}
signature://token生成方使用私匙生成token,token消费方使用用公匙验证token是否被修改过
rsasha256(
  base64urlencode(header) + "." +base64urlencode(payload),public key,private key
  )
expires_in="exp"-"nbf"

identityserver4

客户端凭证模式

不支持刷新令牌、无法访问用户资源scope(openid、profile、email等)

request:
    post /connect/token http/1.1  #请求方式只能为post
    host: idsrv-server.com
    content-type: application/x-www-form-urlencoded #参数只能放在body里面
    body:
    {
        grant_type:client_credentials
        client_id:clientcredentials
        client_secret:iwiaxnzijoibnvsbcisimf1zci6wyjudwxsl3jlc291cmnlcyisim9yzgvycyjdlcjjbgllbnrfawqioijdb
        scope:orders openid(可选,默认请求所有scope)
    }
response:
    http/1.1 200 ok
    content-type: application/json
    cache-control: no-store
    pragma: no-cache
     
    {
      "access_token":"mtq0njjkzmq5otm2nde1ztzjngzmzji3",
      "token_type":"bearer",
      "expires_in":3600
    }

资源所有者密码模式

用于同一组织下授权

#请求token
request:
    post /connect/token http/1.1
    host: idsrv-server.com
    content-type: application/x-www-form-urlencoded
    body:
    {
        grant_type:password
        username:dd
        password:dd
        client_id:eshoponvue
        scope:orders(可选参数)
    }

#请求刷新令牌:原刷新令牌失效、之前颁发的access_token不受影响(需要实现手动失效)
request:
    post /connect/token http/1.1
    host: idsrv-server.com
    content-type: application/x-www-form-urlencoded
    body:
    {
        grant_type:refresh_token
        refresh_token:e4364377ec69c8d5c06a49d7b74efbd2a29015ac37e9ede8e17597d348931d32
        client_id:eshoponvue
    }
respose:
{
    "id_token": "eyjhbgcio.ijsuzi1nii.simtpzcw",
    "access_token": "eyjhb.gcioijsuz.i1niisim",
    "expires_in": 3600,
    "token_type": "bearer",
    "refresh_token": "60e7dda6e30473ce6dc0a1656b38c174a74ef73310d"
}
#通过access_token请求用户终结点(需要scope:profile):/connect/userinfo

简化模式

第三方向授权终结点请求授权,授权成功后,通过url锚点(#)将access_token、id_token传给redirecturl

授权码模式

流程分析

1 identityserver服务端启用服务
2 mvc项目配置oidc保护控制器,并设置clent_id等
3 webapi项目配置bearer认证保护api

1.访问受identityserver oidc保护的mvc控制器
2.自动重定向到identityserver的/connect/authorize,并附带clint信息

idsrv授权码模式:
js客户端mgr.signinredirect()
1.向idsrv服务器请求/.well-known/openid-configuration 获取idsrv数据
2.向/connect/authorize发起授权请求,携带以下参数
client_id: js
redirect_uri:登录成功后跳转的地址
response_type: code
scope:请求的资源权限
state: 2dd196cd7a68402199534d6123791e64
code_challenge: 23kg8msclc2ohdntalrtgelqmnaatadowumlmnenfte
code_challenge_method: s256
3.1.如果验证client信息正确,且携带了idsrv.session和idsrv两个cookie,并已经授权,则跳转到redirect_uri,并携带以下参数给前端页面:
code:授权码
scope:请求的资源权限
state: a656e5bb62024ee48d8267127e46fa68
session_state: yjwa6dw7tre2ii5e0ao6h0y2ty4poifrv4qzn0xvjvi.46fe4aa153c9d5480e0f61406e35e5ff
3.1.1、在redirect_uri页面,通过oidc.usermanager({ response_mode: "query" }).signinredirectcallback(),通过授权码向/connect/token请求token,携带以下参数
client_id: js
code: 725ca140eb5afdbc8f37cda96eeb53550aa4502de462c77d0618eed2353422d4
redirect_uri: http://localhost:5003/callback.html
code_verifier: a6ff87be469a4171bf1bfd43e5310468bf1d196d337244e2a829b0e94fe476bb9fdad37d300048e692c2fe58c734b0b6
grant_type: authorization_code
3.1.2将code、token写入cookie保存,否则下次通过idsrv.session和idsrv两个cookie申请新的授权码,同时再次跳转到初始请求页面
3.2.如果验证client信息,但未授权,则跳转到/account/login并携带一个returnurl参数
该参数为/connect/authorize/callback并附带步骤2的所有参数。该参数需要保存并在登录成功后,跳转到该页面
3.3输入账号密码,进入自定义验证api中
3.4验证成功,通过httpcontext.signinasync方法为用户颁发加密的用户凭证,将idsrv.session和idsrv两个cookie写入请求头
3.5.在自定义api中跳转到returnurl
3.6.1如果未配置授权页面,idsrv服务端将/connect/authorize/callback重定向到redirect_uri,并携带授权码等参数,重复3.1.1
3.6.2如果配置了授权页面,idsrv服务端将/connect/authorize/callback重定向到授权页面

登出操作:
js客户端mgr.signoutredirect()
1.向idsrv请求/connect/endsession 并携带以下两个参数
id_token_hint:
post_logout_redirect_uri: 登出回调地址
2.重定向到/account/logout 并携带生成的logoutid参数
3.在logout里清除await httpcontext.signoutasync() 并跳转到post_logout_redirect_uri