写在前面

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/

4、流程图

  客户端授权模式是最基本的使用场景,我们需要做一个API(受保护的资源),一个客户端(访问的应用),一个IdentityServer(用来授权)

  

一、创建IdentityServer

1、用VS创建一个Web 项目

  

2、添加引用 IdentityServer4 包,下图是我已经安装好了的截图

3、添加一个配置文件(这里也可以使用json文件)

    public class IdpConfig
{
/// <summary>
/// 用户认证信息
/// </summary>
/// <returns></returns>
public static IEnumerable<IdentityResource> GetApiResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Address(),
new IdentityResources.Email(),
new IdentityResources.Phone()
};
}
/// <summary>
/// API 资源
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
} /// <summary>
/// 客户端应用
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
// 客户端ID 这个很重要
ClientId = "client",
//AccessToken 过期时间,默认3600秒,注意这里直接设置5秒过期是不管用的,解决方案继续看下面 API资源添加JWT
//AccessTokenLifetime=5,
// 没有交互性用户,使用 clientid/secret 实现认证。
AllowedGrantTypes = GrantTypes.ClientCredentials,
// 用于认证的密码
ClientSecrets =
{
new Secret("secret".Sha256())
},
// 客户端有权访问的范围(Scopes)
AllowedScopes = { "api1" }
}
};
}
}

4、在StartUp.cs 里注册 IdentityServer4

  ConfigureServices()

    services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
.AddDeveloperSigningCredential()//解决Keyset is missing 错误
//.AddTestUsers(TestUsers.Users)
//.AddInMemoryIdentityResources(IdpConfig.GetApiResources())
.AddInMemoryApiResources(IdpConfig.GetApis())
.AddInMemoryClients(IdpConfig.GetClients());

  Configure()方法添加使用 IdentityServer4 中间件

app.UseIdentityServer();

5、配置完成

  启动项目,访问 http://localhost:5002/.well-known/openid-configuration (我的端口号是5002) ,可以浏览 发现文档,参考下图,说明已经配置成功。

  后面客户端会使用里面的数据进行请求toke

  项目第一次启动根目录也会生成一个文件 tempkey.rsa

  

二、客户端

1、新建一个.Net Core Web 项目

  这里可以使用其他建立客户端 。例如:控制台程序、wpf 等等。需要添加 NuGet 包 IdentityModel

  

2、新建一个 Controller 用来测试访问上面的IdentityServer

  获取token,访问 http://localhost:5003/Idp/token ,提示访问成功

    public class IdpController : Controller
{
private static readonly string _idpBaseUrl = "http://localhost:5002";
public async Task<IActionResult> Token()
{
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync(_idpBaseUrl);
if (disco.IsError)
{
return Content("获取发现文档失败。error:" + disco.Error);
}
var token = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
{
Address = disco.TokenEndpoint,
//ClientId、ClientSecret、Scope 这里要和 API 里定义的Client一模一样
ClientId = "client",
ClientSecret = "secret",
Scope = "api1"
});
if (token.IsError)
{
return Content("获取 AccessToken 失败。error:" + disco.Error);
}
return Content("获取 AccessToken 成功。Token:" + token.AccessToken);
}
}

三、添加API资源

1、新建一个API项目

  我把API项目和IdentityServer 放到同一个解决方案,这个自己定,无所谓的

  API资源指的是IdentityServer IdpConfig.GetApis() 里面添加的 api1(这个api1名称随便起,但是要注意一定要保持一致)

  添加认证之后就可以测试用 AccessToken 请求资源了

2、添加JWT 认证

  StartUp.ConfigureServices()

       services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
// IdentityServer 地址
options.Authority = "http://localhost:5002";
//不需要https
options.RequireHttpsMetadata = false;
//这里要和 IdentityServer 定义的 api1 保持一致
options.Audience = "api1";
//token 默认容忍5分钟过期时间偏移,这里设置为0,
//这里就是为什么定义客户端设置了过期时间为5秒,过期后仍可以访问数据
options.TokenValidationParameters.ClockSkew = TimeSpan.Zero;
options.Events = new JwtBearerEvents
{
//AccessToken 验证失败
OnChallenge = op =>
{
//跳过所有默认操作
op.HandleResponse();
//下面是自定义返回消息
//op.Response.Headers.Add("token", "401");
op.Response.ContentType = "application/json";
op.Response.StatusCode = StatusCodes.Status401Unauthorized;
op.Response.WriteAsync(JsonConvert.SerializeObject(new
{
status = StatusCodes.Status401Unauthorized,
msg = "token无效"
}));
return Task.CompletedTask;
}
};
});

3、添加认证中间件

//这里注意 一定要在 UseMvc前面,顺序不可改变
app.UseAuthentication();

4、Controller 添加特性认证 [Authorize]

    [Route("api/[controller]")]
[Authorize]
public class SuiBianController : Controller
{
[HttpGet]
public string Get()
{
var roles = User.Claims.Where(l => l.Type == ClaimTypes.Role);
return "访问成功,当前用户角色 " + string.Join(',', roles.Select(l => l.Value));
}
}

5、测试

  访问 http://localhost:5001/api/suibian ,提示 token 无效,证明我们增加认证成功

  

四、客户端测试

1、修改 IdpController, 添加一个action 访问 API资源 /api/suibian

    public class IdpController : Controller
{
//内存缓存 需要提前注册 services.AddMemoryCache();
private IMemoryCache _memoryCache;
private static readonly string _idpBaseUrl = "http://localhost:5002";
private static readonly string _apiBaseUrl = "http://localhost:5001";
public IdpController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public async Task<IActionResult> Token()
{
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync(_idpBaseUrl);
if (disco.IsError)
{
return Content("获取发现文档失败。error:" + disco.Error);
}
var token = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "api1"
});
if (token.IsError)
{
return Content("获取 AccessToken 失败。error:" + disco.Error);
}
//将token 临时存储到 缓存中
_memoryCache.Set("AccessToken", token.AccessToken);
return Content("获取 AccessToken 成功。Token:" + token.AccessToken);
} public async Task<IActionResult> SuiBian()
{
string token, apiurl = GetApiUrl("suibian");
_memoryCache.TryGetValue("AccessToken", out token);
if (string.IsNullOrEmpty(token))
{
return Content("token is null");
}
var client = new HttpClient();
client.SetBearerToken(token);
var response = await client.GetAsync(apiurl);
var result = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
_memoryCache.Remove("AccessToken");
return Content($"获取 {apiurl} 失败。StatusCode:{response.StatusCode} \r\n Token:{token} \r\n result:{result}");
}
return Json(new
{
code = response.StatusCode,
data = result
});
} private string GetApiUrl(string address)
{
return _apiBaseUrl + "/api/" + address;
}
}

2、请求 AccessToken

  http://localhost:5003/Idp/token ,请求成功后会将 token 存储到 cache 中

3、请求 API 资源

  http://localhost:5003/Idp/suibian ,token是直接在缓存里面取出来的

五、项目目录

IdentityServer4 (1) 客户端授权模式(Client Credentials)的更多相关文章

  1. (转)基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  2. 基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  3. IdentityServer4(客户端授权模式)

    1.新建三个项目 IdentityServer:端口5000 IdentityAPI:端口5001 IdentityClient: 2.在IdentityServer项目中添加IdentityServ ...

  4. IdentityServer4[3]:使用客户端认证控制API访问(客户端授权模式)

    使用客户端认证控制API访问(客户端授权模式) 场景描述 使用IdentityServer保护API的最基本场景. 我们定义一个API和要访问API的客户端.客户端从IdentityServer请求A ...

  5. IdentityServer(二)客户端授权模式

    前言 客户端授权模,客户端直接向Identity Server申请token并访问资源.客户端授权模式比较适用于服务之间的通信. 搭建Identity服务 新建名为 IdentityServer 的W ...

  6. 基于 IdentityServer3 实现 OAuth 2.0 授权服务【客户端模式(Client Credentials Grant)】

    github:https://github.com/IdentityServer/IdentityServer3/ documentation:https://identityserver.githu ...

  7. IdentityServer4系列 | 客户端凭证模式

    一.前言 从上一篇关于 快速搭建简易项目中,通过手动或者官方模板的方式简易的实现了我们的IdentityServer授权服务器搭建,并做了相应的配置和UI配置,实现了获取Token方式. 而其中我们也 ...

  8. IdentityServer4(7)- 使用客户端认证控制API访问(客户端授权模式)

    一.前言 本文已更新到 .NET Core 2.2 本文包括后续的Demo都会放在github:https://github.com/stulzq/IdentityServer4.Samples (Q ...

  9. OAuth2:客户端证书授权(Client Credentials)类型的开放授权

    适应范围 认证服务器不提供像用户数据这样的重要资源,仅仅是有限的只读资源或者一些开放的API.例如使用了第三方的静态文件服务,如Google Storage或Amazon S3.这样,你的应用需要通过 ...

随机推荐

  1. postman 进阶技巧

    cookie 清除缓存 code 生成接口自动化测试脚本 响应部分 pretty 响应以json或xml显示 raw 响应以文本显示 preview 以HTML网页行驶显示 断言 断言:用于判断接口请 ...

  2. day04 python入门(变量,基本数据类型)

    python入门学习 来自egon的学习套路 在每次遇到一个新事物的时候,要学三步: xxx是什么? 为什么要有xxx? ​ 大前提:python中所有出现的语法都是为了让计算机能够具有人的某一个功能 ...

  3. 主题博客添加 h5 贴边音乐插件

    前言: 前几日,在逛微博的时候,发现微博主页的左下角有一个贴边的音乐小插件,我顿时就想在自己博客上也弄一个玩玩.当时就想把微博那个移植过来,首先我用谷歌浏览器F12 查看页面源码,和检查元素代码,发现 ...

  4. hihoCoder 1049 后序遍历 最详细的解题报告

    题目来源:后序遍历 解题思路:开始时我只知道先通过先序.中序求出二叉树,然后再后序遍历二叉树,这当然也是一种解题思路,但是会做一些无用功,比如:计算二叉树.其实,可以直接通过先序序列和中序序列直接求出 ...

  5. Quartz.Net系列(十三):DateBuilder中的API详解

    1.DateOf.ToDayAt.TomorrowAt DateOf:指定年月日时分秒 public static DateTimeOffset DateOf(int hour, int minute ...

  6. 关于报错,Whoops! Lost connection to ws://XXX.XXX.XXX.XXX:15684/ws

    昨天,在玩rabbitMQ时候,用stompJS从web连接ranbbitMQ时,报了标题的错误消息! 我把我这个html页面代码贴上,简单得讲,就是断开后,重新连接即可.

  7. vue配置 less 全局变量

    在使用Vue开发的过程中,通常会用到一些样式的全局变量,如果在每个组件中引入就太繁琐了,维护性也不好,因此全局引入是个不错的想法.下面以less为例,记录一下全局引入less变量的步骤: 1.首先安装 ...

  8. Mock分页

    前后端分离开发时,一般会使用mock. 因为mock是用node运行的,行为与调用后台一致. 这样,不需要等后台写好,只要有接口文档,前端可以自己调接口,这样联调时遇到的问题会少很多,可以加快整体开发 ...

  9. springboot+junit测试

    文章目录 一.junit断言 二.测试模块 三.使用Mockito作为桩模块 四.使用mockMvc测试web层 五.批量测试和测试覆盖率 参考视频:用Spring Boot编写RESTful API ...

  10. 从零开始一起学Blazor WebAssembly 开发(4)

    登录模块基本完成了,登录主要用了以下几个点: 1.后端采用的Abp Vnext 框架,这个框架自带的IdentityServer4用户角色权限控制,这个框架登录研究了好一阵子,有几个坑这里说下: 1) ...