一. PKCE机制
1. 准备
(1). IDS4_Server1:认证授权服务器
(2). MvcClient1:web客户端
然后将上述两个项目配置成授权码模式(如何配置见上一节 IdentityServer4授权码模式介绍和代码实操演练)
PS: PKCE机制是在授权码模式的基础上,增加了几个验证参数,使其更加安全。
2. 代码配置
(1).IDS4_Server1中的Config1,新增 RequirePkce = true, 开启Pkce授权校验。
(2).MvcClient1中的ConfigureServices中, 新增options.UsePkce = true;开启Pkce. (默认就是true,所以可以省略)
PS:实际上在上一节的授权码模式中已经开启了pkce,只是没有单独点明增加的参数的含义。
3. 剖析测试
(1).在导向认证服务器的请求和确认授权页面的请求中,新增两个参数:code_challenge 和 code_challenge_method.
(2).客户端携带授权码请求认证服务器的时候,携带的参数中新增: code_verifier
二. 令牌刷新机制
1. 准备
(1). IDS4_Server1:认证授权服务器
(2). MvcClient1:web客户端
然后将上述两个项目配置成授权码模式(如何配置见上一节 IdentityServer4授权码模式介绍和代码实操演练)
2.代码配置
(1).IDS4_Server1中的Config1,新增如下代码:
(2).MvcClient1中的ConfigureServices中,新增如下代码:
options.Scope.Add(OpenIdConnectScope.OfflineAccess);
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(1);
options.TokenValidationParameters.RequireExpirationTime = true;
3.运行结果
页面显示多了个: refresh_token
注意过期时间:Token.expires_at
三. 混合授权模式
1. 背景
access token 不含有任何关于身份认证的信息(用户声明信息),access token 的生命期可能会非常的长,即使用户离开了它仍有可能有效,它还有可能被用于无最终用户参与的情况,还有一种情况就是 access token 可能会被其它的客户端应用借用。所以,无论客户端是如何得到的 access token, 它都无法从 access token 里得到最终用户的信息以及最终用户的身份认证状态(用户声明信息)。
在 OAuth2.0 里,access token 不是为客户端准备的,它对于客户端应该是不透明的, 但是客户端也需要从 access token 得到一些用户信息,实际上客户端应用只是 access token 的展示者, access token
真正的目标观众是被保护的资源.
在 OpenID Connect 里,加了一个 ID Token 令牌,它会和 access token 一同发送给客户端用,用于识别当前用户是他声称的的用户.
2. 核心代码
IDS4服务器:AllowedGrantTypes = GrantTypes.Hybrid
代码分享:
/// <summary>
/// 混合模式
/// </summary>
public class Config2
{
/// <summary>
/// IDS资源
/// </summary>
/// <returns></returns>
public static IEnumerable<IdentityResource> GetIds()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
/// <summary>
/// 可以使用ID4 Server 客户端资源
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
List<Client> clients = new List<Client>() {
new Client
{
ClientId = "client1",
ClientSecrets = { new Secret("123456".Sha256()) },
//混合模式
AllowedGrantTypes = GrantTypes.Hybrid,
//需要确认授权
RequireConsent = true,
//关闭PKCE校验(默认是true)
RequirePkce = false,
//允许token通过浏览器
AllowAccessTokensViaBrowser=true,
// where to redirect to after login(登录)
RedirectUris = { "http://127.0.0.1:7072/signin-oidc" },
// where to redirect to after logout(退出)
PostLogoutRedirectUris = { "http://127.0.0.1:7072/signout-callback-oidc" },
//允许的范围
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
},
AlwaysIncludeUserClaimsInIdToken=true,
//允许脱机访问
AllowOfflineAccess=true,
//accessToken有效期,默认事3600秒,即1小时 (单位:秒)
AccessTokenLifetime = 600
}
};
return clients;
}
/// <summary>
/// 定义可以使用ID4的用户资源
/// </summary>
/// <returns></returns>
public static List<TestUser> GetUsers()
{
var address = new
{
street_address = "One Hacker Way",
locality = "Heidelberg",
postal_code = 69118,
country = "Germany"
};
return new List<TestUser>()
{
new TestUser
{
SubjectId = "001",
Username = "ypf1", //账号
Password = "123456", //密码
Claims =
{
new Claim(JwtClaimTypes.Name, "Alice Smith"),
new Claim(JwtClaimTypes.GivenName, "Alice"),
new Claim(JwtClaimTypes.FamilyName, "Smith"),
new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"),
new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
new Claim(JwtClaimTypes.WebSite, "http://alice.com"),
new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(address), IdentityServerConstants.ClaimValueTypes.Json)
}
},
new TestUser
{
SubjectId = "002",
Username = "ypf2",
Password = "123456",
Claims =
{
new Claim(JwtClaimTypes.Name, "Bob Smith"),
new Claim(JwtClaimTypes.GivenName, "Bob"),
new Claim(JwtClaimTypes.FamilyName, "Smith"),
new Claim(JwtClaimTypes.Email, "BobSmith@email.com"),
new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
new Claim(JwtClaimTypes.WebSite, "http://bob.com"),
//这是新的序列化模式哦
new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(address), IdentityServerConstants.ClaimValueTypes.Json)
}
}
};
}
}
Mvc客户端:options.ResponseType = OpenIdConnectResponseType.CodeIdToken
代码分享:
{
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
//添加Cookie认证
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
//通过OIDC协议远程请求认证
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "http://127.0.0.1:7070"; //认证授权服务器地址
options.RequireHttpsMetadata = false;
options.ClientId = "client1"; //客户端ID
options.ClientSecret = "123456"; //客户端秘钥
//混合模式
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.ResponseMode = OpenIdConnectResponseMode.FormPost;
options.SaveTokens = true;
//开启token时间的校验
options.Scope.Add(OpenIdConnectScope.OfflineAccess);
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(1);
options.TokenValidationParameters.RequireExpirationTime = true;
});
}
特别注意:要关闭pkce的验证,否则会报错 code challenge required. 代码:RequirePkce = false
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
来源:oschina
链接:https://my.oschina.net/u/4350591/blog/4340594