该项目使用dotnet版本3.1 ,vs code创建
创建Web MVC项目
创建命令
dotnet new mvc --name WebMvc
修改./properties/launchSettings.json
"profiles": {
"WebApi": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "http://localhost:5002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
添加登录验证
运行下面命令安装
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 3.1.0
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect --version 3.1.0
在startup.cs中的ConfigureServices类中添加
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // 关闭了JWT的Claim 类型映射, 以便允许well-known claims.
services.AddAuthentication(options => // 将身份验证服务添加到DI
{
options.DefaultScheme = "Cookies"; // 使用cookie来登录用户
options.DefaultChallengeScheme = "oidc"; // 登录时使用OpenID Connect
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options => // 配置执行OpenID Connect
{
options.Authority = "http://localhost:5000"; // IdentityServer地址
options.RequireHttpsMetadata = false; // 是否需要HTTPS
options.ClientId = "mvc";
options.SaveTokens = true;
});
在startup.cs中的Configure类中添加 认证中间件
app.UseAuthentication();
然后在HomeController中Privacy添加 Authorize属性
然后AuthServer程序中的config.cs文件中将client修改如下
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Implicit,
// AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
// RequirePkce = true,
// ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) },
RedirectUris = { "http://localhost:5002/signin-oidc" }, // login
// FrontChannelLogoutUri = "http://localhost:5003/signout-oidc",
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" }, // logout
AllowOfflineAccess = true,
AllowedScopes = { "openid", "profile", "api1" }
},
在./view/home/Privacy.cshtml添加如下代码来显示登录成功的用户信息
@using Microsoft.AspNetCore.Authentication
<h2>Claims</h2>
<div>
<strong>id_token</strong>
<span>@await ViewContext.HttpContext.GetTokenAsync("id_token")</span>
</div>
<div>
<strong>access_token</strong>
<span>@await ViewContext.HttpContext.GetTokenAsync("access_token")</span>
</div>
<dl>
@foreach (var claim in User.Claims)
{
<dt>@claim.Type</dt>
<dd>@claim.Value</dd>
}
</dl>
开启AuthServer 和 WebMvc 程序,访问 http://localhost:5002/ ,点击 Privacy 会跳到AuthServer的登录页面
输入账号 bob 密码 bob 后跳到如下页面
点击YES后重定向返回 Privacy 页面,可以看到返回的信息,但access_token没有返回
原因需要在上述修改的AuthServer文件中config的client加上
AllowAccessTokensViaBrowser = true
还要在WebMvc文件中的startup的 ConfigureServices 的 AddOpenIdConnect 加上
options.ResponseType = "id_token token";
重启两个程序,退出登录(登出功能在下文),重新登录即可
登出
在HomeController类中添加
public IActionResult Logout()
{
return SignOut("Cookies", "oidc");
}
在view/shared/_layout.cshtml添加
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Logout">logout</a>
</li>
重启服务,刷新页面,点击logout,会跳到AuthServer的登出页面
提供access token和refresh tokens来访问api
使用refresh tokens来重新获取新的access token,确保会话不会断
首先,将AuthServer项目的config文件中client修改如下
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Hybrid, // GrantTypes.HybridAndClientCredentials 也可以
ClientSecrets = { new Secret("secret".Sha256()) },
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowOfflineAccess = true,
AllowedScopes = { "openid", "profile", "api1" },
AllowAccessTokensViaBrowser = true
},
然后在WebMvc项目的startup文件中的ConfigureServices修改如下
.AddOpenIdConnect("oidc", options => // 配置执行OpenID Connect
{
options.Authority = "http://localhost:5000"; // IdentityServer地址
options.RequireHttpsMetadata = false; // 是否需要HTTPS
options.SignInScheme = "Cookies";
options.ClientId = "mvc";
options.SaveTokens = true;
options.ResponseType = "id_token code";
options.ClientSecret = "secret";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
});
在WebMvc项目view/home/privacy.cshtml中添加
<div>
<strong>refresh_token</strong>
<span>@await ViewContext.HttpContext.GetTokenAsync("refresh_token")</span>
</div>
运行
登录后,显示多出refresh_token
打开postman使用refresh_token(注意:只能使用一次)来重新获取access token