写在前面

1、源码(.Net Core 2.2)

  git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git

2、相关章节

  2.1、《IdentityServer4 (1) 客户端授权模式(Client Credentials)
  2.2、《IdentityServer4 (2) 密码授权(Resource Owner Password)
  2.3、《IdentityServer4 (3) 授权码模式(Authorization Code)
  2.4、《IdentityServer4 (4) 静默刷新(Implicit)》
  2.5、《IdentityServer4 (5) 混合模式(Hybrid)》

3、参考资料

  IdentityServer4 中文文档 http://www.identityserver.com.cn/
  IdentityServer4 英文文档 https://identityserver4.readthedocs.io/en/latest/

  OpenID Connect 官网 https://openid.net/connect/
  OpenID Connect 中文 https://www.cnblogs.com/linianhui/p/openid-connect-core.html
  OpenID Connect和OAuth 2.0对比:https://www.jianshu.com/p/d453076e6433

4、流程图

  1、访问客户端受保护的url
  2、跳转到授权服务器认证
  3、用户填写认证(账号密码)
  4、认证成功,选择授权的scope
  5、授权成功(点击同意授权),携带授权码code返回客户端
  6、客户端通过后台通信请求AccessToken 和IdToken,如果设置了 OfflineAccess=true也会返回RefreshToken(可以刷新AccessToken)

  整个访问流程建议使用fiddler 抓包查看,更好的了解

一、服务端

1、下载一个官方示例

  地址:https://github.com/IdentityServer/IdentityServer4.Quickstart.UI

  根据自己使用的Core 版本下载对应的,点击 tags 里找,我下载的是2.5,解压后如下图

  

2、新建一个 web 项目 .NetCore 2.2版本

   把官网下载的文件添加到项目中,Quickstart 我换成了Controllers

3、添加配置类 (IdpConfig.cs)

  参看 《IdentityServer4 (1) 客户端授权模式(Client Credentials)》里的,直接复制过来就可以了

4、添加客户端

  IdpConfig.cs GetClients()

  AllowedScopes 属性设置的值,必须在GetApiResources()  GetApis() 里提前定义好,并且在 StartUp.cs 里已经注册

   new Client{
ClientId="mvc client", //客户端Id
ClientName="测试客户端", //客户端名称 随便写
AllowedGrantTypes=GrantTypes.Code,//验证模式
ClientSecrets=
{
new Secret("mvc secret".Sha256()) //客户端验证密钥
},
// 登陆以后 我们重定向的地址(客户端地址),
// {客户端地址}/signin-oidc是系统默认的不用改,也可以改,这里就用默认的
RedirectUris = { "http://localhost:5003/signin-oidc" },
//注销重定向的url
PostLogoutRedirectUris = { "http://localhost:5003/signout-callback-oidc" },
//是否允许申请 Refresh Tokens
//参考地址 https://identityserver4.readthedocs.io/en/latest/topics/refresh_tokens.html
AllowOfflineAccess=true,
//将用户claims 写人到IdToken,客户端可以直接访问
AlwaysIncludeUserClaimsInIdToken=true,
//客户端访问权限
AllowedScopes =
{
"api1",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Address,
IdentityServerConstants.StandardScopes.Phone,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess
}
}

5、注册相关信息(StartUp.cs)

  ConfigureServices() 注意这里我修改了路径,如果你使用的是 git 下载下来的不需要修改,我这里修改是我把 git 下载的改动了

    services.AddIdentityServer(options =>
{
//默认的登陆页面是/account/login
options.UserInteraction.LoginUrl = "/login";
//授权确认页面 默认/consent
//options.UserInteraction.ConsentUrl = "";
})
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(IdpConfig.GetApis())
.AddInMemoryClients(IdpConfig.GetClients())
.AddTestUsers(TestUsers.Users)
.AddInMemoryIdentityResources(IdpConfig.GetApiResources());

  Configure()

   // 要写在 UseMvc()前面
app.UseIdentityServer();
app.UseMvcWithDefaultRoute();

二、客户端

1、添加认证相关信息(StartUp.cs)

  ConfigureServices()

   //关闭了 JWT 身份信息类型映射
//这样就允许 well-known 身份信息(比如,“sub” 和 “idp”)无干扰地流过。
//这个身份信息类型映射的“清理”必须在调用 AddAuthentication()之前完成
//区别可参考下面截图
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
//添加认证信息
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//认证服务器
options.Authority = "http://localhost:5002";
//去掉 https
options.RequireHttpsMetadata = false;
options.ClientId = "mvc client";
options.ClientSecret = "mvc secret";
//把 token 存储到 cookie
options.SaveTokens = true;
options.ResponseType = OpenIdConnectResponseType.Code;
//添加申请 权限 ,这里的 scope 必须在授权服务端定义的客户端 AllowedScopes 里
options.Scope.Clear();
options.Scope.Add("api1");
options.Scope.Add(OidcConstants.StandardScopes.OpenId);
options.Scope.Add(OidcConstants.StandardScopes.Email);
options.Scope.Add(OidcConstants.StandardScopes.Address);
options.Scope.Add(OidcConstants.StandardScopes.Phone);
options.Scope.Add(OidcConstants.StandardScopes.Profile);
options.Scope.Add(OidcConstants.StandardScopes.OfflineAccess); options.Events = new OpenIdConnectEvents
{
OnAuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.WriteAsync("验证失败");
return Task.CompletedTask;
}
};
});

  Configure()

   //写在 UseMvc() 前面
app.UseAuthentication();
app.UseMvcWithDefaultRoute();

  JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 区别

2、添加测试Controller

    [Authorize]
public class TestController : Controller
{
/// <summary>
/// 测试从服务端认证
/// </summary>
/// <returns></returns>
public async Task<IActionResult> Private()
{
var accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
var idToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken); var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
var code = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.Code); var model = new HomeViewModel
{
Infos = new Dictionary<string, string>()
{
{"AccessToken", accessToken },
{"IdToken", idToken },
{"RefreshToken", refreshToken },
{"Code", code } //code 是空 因为code 是一次性的
}
};
return View(model);
} /// <summary>
/// 测试请求API资源(api1)
/// </summary>
/// <returns></returns>
public async Task<IActionResult> SuiBian()
{
var accesstoken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
if (string.IsNullOrEmpty(accesstoken))
{
return Json(new { msg = "accesstoken 获取失败" });
}
var client = new HttpClient();
client.SetBearerToken(accesstoken);
var httpResponse = await client.GetAsync("http://localhost:5001/api/suibian");
var result = await httpResponse.Content.ReadAsStringAsync();
if (!httpResponse.IsSuccessStatusCode)
{
return Json(new { msg = "请求 api1 失败。", error = result });
}
return Json(new
{
msg = "成功",
data = JsonConvert.DeserializeObject(result)
});
}
}

三、API资源

参考上一篇《IdentityServer4 (1) 客户端授权模式》

修改SuiBianController.Get()

   [HttpGet]
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}

四、测试

1、端口说明

  【客户端:5003】【 API :5001 】【 授权认证服务器:5002】,并确认3个端口可以正常访问

  

2、客户端访问

  2.1 、输入地址:http://localhost:5003/test/private 查看是否可正常跳转到授权服务器,   

  

  2.2、正常跳转,输入账号(alice)密码(alice)并登陆。登陆成功,并显示可授权的信息

  

  2.3、点击授权同意,返回相关授权信息,并展示在页面

  

  2.4 、输入地址 http://localhost:5003/test/suibian 访问 API 资源,正确返回

    

IdentityServer4 (3) 授权码模式(Authorization Code)的更多相关文章

  1. 基于OWIN WebAPI 使用OAUTH2授权服务【授权码模式(Authorization Code)】

    之前已经简单实现了OAUTH2的授权码模式(Authorization Code),但是基于JAVA的,今天花了点时间调试了OWIN的实现,基本就把基于OWIN的OAUHT2的四种模式实现完了.官方推 ...

  2. Apache Oltu 实现 OAuth2.0 服务端【授权码模式(Authorization Code)】

    要实现OAuth服务端,就得先理解客户端的调用流程,服务提供商实现可能也有些区别,实现OAuth服务端的方式很多,具体可能看 http://oauth.net/code/ 各语言的实现有(我使用了Ap ...

  3. IdentityServer4系列 | 授权码模式

    一.前言 在上一篇关于简化模式中,通过客户端以浏览器的形式请求IdentityServer服务获取访问令牌,从而请求获取受保护的资源,但由于token携带在url中,安全性方面不能保证.因此,我们可以 ...

  4. OAuth 第三方登录授权码(authorization code)方式的小例子

    假如上面的网站A,可以通过GitHub账号登录: 下面以OAuth其中一种方式,授权码(authorization code)方式为例. 一.第三方登录的原理 所谓第三方登录,实质就是 OAuth 授 ...

  5. OAuth 白话简明教程 2.授权码模式(Authorization Code)

    转自:http://www.cftea.com/c/2016/11/6703.asp OAuth 白话简明教程 1.简述 OAuth 白话简明教程 2.授权码模式(Authorization Code ...

  6. OAuth2.0 授权许可 之 Authorization Code

    写在前面: 在前一篇博客<OAuth2.0 原理简介>中我们已经了解了OAuth2.0的原理以及它是如何工作的,那么本篇我们将来聊一聊OAuth的一种授权许可方式:授权码(Authoriz ...

  7. asp.net权限认证:OWIN实现OAuth 2.0 之授权码模式(Authorization Code)

    asp.net权限认证系列 asp.net权限认证:Forms认证 asp.net权限认证:HTTP基本认证(http basic) asp.net权限认证:Windows认证 asp.net权限认证 ...

  8. IdentityServer4实现OAuth2.0四种模式之授权码模式

    接上一篇:IdentityServer4实现OAuth2.0四种模式之隐藏模式 授权码模式隐藏码模式最大不同是授权码模式不直接返回token,而是先返回一个授权码,然后再根据这个授权码去请求token ...

  9. IdentityServer4系列[6]授权码模式

    授权码模式是一种混合模式,是目前功能最完整.流程最严密的授权模式.它主要分为两大步骤:认证和授权.其流程为: 用户访问客户端,客户端将用户导向Identity Server. 用户填写凭证信息向客户端 ...

随机推荐

  1. java 面向对象(三十八):反射(二) Class类的理解与获取Class的实例

    1.Class类的理解 1.类的加载过程:程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾).接着我们使用java.exe命令对某个字节码文件进行解释运行.相当于将某个 ...

  2. python 装饰器(五):装饰器实例(二)类装饰器(类装饰器装饰函数)

    回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文). 那么用类来实现也是也可以的.我们可以让类的构造函数__init__()接受一个函 ...

  3. Ethical Hacking - NETWORK PENETRATION TESTING(5)

    Deauthentication Attacks Theory This attack is used to disconnect any device from any network within ...

  4. 使用PowerShell自动编译部署前端

    前言 最近在开发一套管理系统,做了前后端分离. 后台使用的是Asp.Net Core 3.1 前端使用的是Vue+Ant Design 自己搞了一台云服务器,打算把系统部署到云服务器上.以供外网访问. ...

  5. Fisher算法+两类问题

    文章目录 一.Fisher算法 二.蠓的分类问题: 三.代码实现: 一.Fisher算法 二.蠓的分类问题: 两种蠓Af和Apf已由生物学家根据它们的触角和翼长加以区分(Af是能传播花粉的益虫,Apf ...

  6. Java中Map的entrySet()详解

    转发:原博客 由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系.Map中采用Entry内部类来表示一个映射项,映射项包含Key和ValueMap.Entry里面包含getKey() ...

  7. C++语法小记---类模板

    类模板 类模板和函数模板类似,主要用于定义容器类 类模板可以偏特化,也可以全特化,使用的优先级和函数模板相同 类模板不能隐式推倒,只能显式调用 工程建议: 模板的声明和实现都在头文件中 成员函数的实现 ...

  8. .net core https 双向验证

    文章来自:https://www.cnblogs.com/axzxs2001/p/10070562.html 关于https双向认证的知识可先行google,这时矸接代码. 为了双向认证,我们首先得准 ...

  9. xctf-pwn hello_pwn

    走流程,看看文件类型 64位,开了NX 直接丢IDA分析 查看sub_400686() 是个给flag的函数,可以看到,只要满足if语句的条件使dword_60106C == 1853186401就可 ...

  10. Vue脚手架创建项目出现 (Failed to download repo vuejs-templates/webpack: Response code 404)

    搭建好(脚手架2.X版本)环境像往常一样使用vue init webpack xxxx 创建项目可以是没多久就开始报错了 报错结果就是:vue-cli · Failed to download rep ...