本文中的IdentityServer4基于上节的jenkins 进行docker自动化部署。

使用了MariaDB,EF Core,AspNetIdentity,Docker

Demo地址:https://sso.neverc.cn

Demo源码:https://github.com/NeverCL/Geek.IdentityServer4

简介

OpenID Connect :常用的认证协议有SAML2p, WS-Federation and OpenID Connect – SAML2p。OpenID Connect是其中最新的协议。

OAuth 2.0 :OAuth 2.0 是一种授权协议。通过Access Token可以访问受保护的API接口。

OpenID Connect和OAuth 2.0非常相似,实际上,OpenID Connect是OAuth 2.0之上的一个扩展。

身份认证和API访问这两个基本的安全问题被合并为一个协议 - 往往只需一次往返安全令牌服务。

IdentityServer4基于ASP.NET Core 2对这两种协议的实现。

支持规范:https://identityserver4.readthedocs.io/en/release/intro/specs.html

关键词

IdentityServer:提供OpenID Connect and OAuth 2.0 protocols.

User:IdentityServer中的用户

Client:第三方应用,包括web applications, native mobile or desktop applications, SPAs etc.

Resource:包含Identity data 和 APIs。这是认证授权中的标识。

Identity Token:标识认证信息,至少包含user的sub claim。

Access Token:标识授权信息,可以包含Client 和 user的claim信息。

授权方式

Client Credentials

Client Credentials是最简单的一种授权方式。

步骤:

  1. 创建IdentityServer

    1. 定义APIs
    2. 定义Client
  2. 创建API
    1. 定义Authentication
  3. 使用Client
    1. 请求Token
    2. 使用Token

IdentityServer:

dotnet new web -o Geek.IdentityServer4 && dotnet add Geek.IdentityServer4 package IdentityServer4

Startup:

services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
...
app.UseIdentityServer();

Config:

public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1")
};
} public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = { new Secret("secret".Sha256()) },
Claims = { new Claim("name","名称") },
AllowedScopes = { "api1" }
},
}
}

API:

dotnet new web -o Geek.Api && dotnet add Geek.Api package IdentityServer4.AccessTokenValidation

Startup:

services.AddMvc();
services.AddAuthentication("Bearer")//AddIdentityServerAuthentication 默认SchemeName:Bearer
.AddIdentityServerAuthentication(opt =>
{
opt.ApiName = "api1";
opt.Authority = "https://sso.neverc.cn";
});
...
app.UseAuthentication();
app.UseMvc();

Controller:

[Route("identity")]
[Authorize]
public class IdentityController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
}

Client:

dotnet new web -o Geek.Client && dotnet add Geek.Client package IdentityServer4.IdentityModel

Program:

var disco = await DiscoveryClient.GetAsync("https://sso.neverc.cn");
var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1"); var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = await client.GetAsync("http://localhost:5001/identity");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(JArray.Parse(content));

ResourceOwnerPassword

这种认证方式需要User提供用户名和密码,所以Client为非常可信的应用才可能使用这种方式。

步骤:

  1. 定义RO Client 和 User
  2. 使用Client

Identity Server

Config:

public static IEnumerable<Client> GetClients()
{
...
new Client
{
ClientId = "ro.client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) },
AllowedScopes = { "api1" }
}
}
public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password",
}
}
}

Startup:

services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers());

Client

var disco = await DiscoveryClient.GetAsync("https://sso.neverc.cn");
var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = await client.GetAsync("http://localhost:5001/identity");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(JArray.Parse(content));

区分Client Credentials 和 ResourceOwnerPassword 可通过 sub claim来区分

Implicit

Implicit为隐式模式,通过浏览器端直接传输id_token

步骤:

  1. 配置IdentityServer

    1. 定义IdentityResources
    2. 定义mvc client
    3. 添加Mvc UI
  2. 创建mvc client

IdentityServer

public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
} ...
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Implicit,
ClientSecrets = { new Secret("secret".Sha256()) },
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
}
}
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers())
.AddInMemoryIdentityResources(Config.GetIdentityResources());

添加MvcUI:

在IdentityServer项目中powershell执行:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))

MvcClient

public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddMvc();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://sso.neverc.cn";
options.ClientId = "mvc";
options.SaveTokens = true;
});
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
app.UseMvcWithDefaultRoute();
}
public class HomeController : ControllerBase
{
[Authorize]
public ActionResult Index()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
}

Hybrid

在Implicit方式中,id_token在浏览器中传输是适用的,但是access_token不应该暴露在浏览器中。

Hybrid模式则是在Implicit的基础上,再传输code,适用code模式来获取access_token。

步骤:

  1. 定义Client
  2. 使用Client

IdentityServer配置

Config:

new Client
{
ClientId = "hybrid",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets = { new Secret("secret".Sha256()) },
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
};

MvcClient配置

Startup:

.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://sso.neverc.cn";
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.Scope.Add("api1");
});

Controller:

public async Task<IActionResult> CallApiUsingUserAccessToken()
{
var accessToken = await HttpContext.GetTokenAsync("access_token"); var client = new HttpClient();
client.SetBearerToken(accessToken);
var content = await client.GetStringAsync("http://localhost:5001/identity"); ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}

在登录完成后,即可通过认证得到的access_token调用CallApiUsingUserAccessToken来调用API服务。

总结

本文为IdentityServer4做了基本的介绍。

实际上IdentityServer4还可以非常灵活的与ASP.NET Identity 以及 EF Core等组合使用。

另外基于ASP.NET Core,所以IdentityServer4也支持跨平台。

【.NET Core】ASP.NET Core之IdentityServer4(1):快速入门的更多相关文章

  1. .NET Core & ASP.NET Core 1.0在Redhat峰会上正式发布

    众所周知,Red Hat和微软正在努力使.NET Core成为Red Hat企业版Linux (RHEL)系统上的一流开发平台选项.这个团队已经一起工作好几个月了,RHEL对.NET有许多需求.今天在 ...

  2. .NET Core & ASP.NET Core 1.0

    .NET Core & ASP.NET Core 1.0在Redhat峰会上正式发布 众所周知,Red Hat和微软正在努力使.NET Core成为Red Hat企业版Linux (RHEL) ...

  3. Do You Kown Asp.Net Core -- Asp.Net Core 2.0 未来web开发新趋势 Razor Page

    Razor Page介绍 前言 上周期待已久的Asp.Net Core 2.0提前发布了,一下子Net圈热闹了起来,2.0带来了很多新的特性和新的功能,其中Razor Page引起我的关注,作为web ...

  4. ASP.NET Core 配置 Entity Framework Core - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 配置 Entity Framework Core - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 配置 Entity Fram ...

  5. .NET Core ASP.NET Core Basic 1-2 控制反转与依赖注入

    .NET Core ASP.NET Core Basic 1-2 本节内容为控制反转与依赖注入 简介 控制反转IOC 这个内容事实上在我们的C#高级篇就已经有所讲解,控制反转是一种设计模式,你可以这样 ...

  6. [.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢?

    [.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢? 在ASP.NET Core应用程序中,接 ...

  7. 使用ASP.NET 构建 Web 应用程序快速入门-8小时的免费培训视频

    - Scott Hanselman的中文博客[转载] [原文发表地址] Building Web Apps with ASP.NET Jump Start - 8 Hours of FREE Trai ...

  8. [译]初识.NET Core & ASP.NET Core

    原文:点这 本文的源代码在此: ASP.NET From Scratch Sample on GitHub 你过你是.NET Core的入门者,你可以先看看下面这篇文章: ASP.NET and .N ...

  9. ASP.NET Core - ASP.NET Core MVC 的功能划分

    概述 大型 Web 应用比小型 Web 应用需要更好的组织.在大型应用中,ASP.NET MVC(和 Core MVC)所用的默认组织结构开始成为你的负累.你可以使用两种简单的技术来更新组织方法并及时 ...

  10. 比较ASP.NET和ASP.NET Core[经典 Asp.Net v和 Asp.Net Core (Asp.Net Core MVC)]

    ASP.NET Core是.与.Net Core FrameWork一起发布的ASP.NET 新版本,最初被称为ASP.NET vNext,有一系列的命名变化,ASP.NET 5.0,ASP.NET ...

随机推荐

  1. XML文档操作之JAXP下实现

    JAXP是java API for xml PRocessing的缩写. 其API可以在javax.xml.parsers 这个包中找到.这个包向用户提供了两个最重要的工厂类,SAXParserFac ...

  2. APACHE,NGINX 详细分析

    Apache是目前最流行的Web应用服务器,占据了互联网应用服务器70%以上的份额.Apache能取得如此成功并不足为奇:它免费.稳定且性能卓越:但Apache能取得如此佳绩的另一个原因是,当时互联网 ...

  3. 【一天一道LeetCode】#93. Restore IP Addresses

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  4. jsoup详解

    json相信大家都用的多,jsonp我就一直没有机会用到,但也经常看到,只知道是"用来跨域的",一直不知道具体是个什么东西.今天总算搞明白了.下面一步步来搞清楚jsonp是个什么玩 ...

  5. Socket编程实践(4) --多进程并发server

    1.Socket地址复用 int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); in ...

  6. java,http的post和get

    使用Java发送GET.POST请求 --节选自<疯狂Java讲义>    URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和 UR ...

  7. Linux环境编程导引

    计算机系统硬件组成 总线 贯穿整个系统的一组电子管道称为总线, 分为: 片内总线 系统总线 数据总线DB 地址总线AB 控制总线CB 外部总线 I/O设备 I/O设备是系统与外界联系的通道 键盘鼠标是 ...

  8. [加密]C#实现维吉尼亚加密与解密(解密前提为已知密匙)

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  9. (二十五)键盘的设置与TextField细节处理

    设置Return Key类型为Send并且勾选下面的复选框即可实现没有内容时禁用keyboard,有内容自动启用. 文本框左边框与文本留有间距的方法: //文本框左侧留下间距 UIView *left ...

  10. spring 注解模式 详解

    Spring基于注解实现Bean定义支持如下三种注解: Spring自带的@Component注解及扩展@Repository.@Service.@Controller,如图12-1所示: JSR-2 ...