OiDc可以说是OAuth的改造版,在最初的OAuth中,我们需要先请求一下认证服务器获取下Access_token,然后根据Access_token去Get资源服务器,
况且OAuth1 和 2 完全不兼容,易用性差,而OIDC可以在登陆的时候就把信息返回给你,不需要你在请求一下资源服务器。下面我们根据Oidc来做一个单点登录。

  新建三个项目(.NET Core
Mvc)两个Client(端口5001,5002),一个Server(5000),首先在Server中添加IdentityServer4的引用。

  在Server中Config.cs用于模拟配置。
public class Config { public static IEnumerable<ApiResource> GetApiResource() {
return new List<ApiResource> { new ApiResource("api","My Api App") }; } public
static IEnumerable<Client> GetClients() { return new List<Client> { new
Client() { ClientId= "mvc", AllowedGrantTypes = GrantTypes.Implicit,
ClientSecrets={ new Secret("secret".Sha256()) }, RequireConsent = false,
RedirectUris= {"http://localhost:5001/signin-oidc", "
http://localhost:5002/signin-oidc" } , PostLogoutRedirectUris = {"
http://localhost:5001/signout-callback-oidc" , "
http://localhost:5002/signout-callback-oidc" }, AllowedScopes = {
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OpenId } } }; }public static
List<TestUser> GetTestUsers() { return new List<TestUser> { new TestUser() {
SubjectId= "10000", Username = "zara", Password = "112233" } }; } public static
IEnumerable<IdentityResource> GetIdentityResources() { return new
List<IdentityResource> { new IdentityResources.OpenId(), new
IdentityResources.Profile(),new IdentityResources.Email() }; } }

GetClient方法中字段为RedirectUris是登陆成功返回的地址,并且我们采用隐式模式(因为只是传统web中传递Access_Token),RequireConsent是否出现同意授权页面,这个我们后续再细说.写完Config.cs后,我们需要依赖注入到IdentityServer中。
public void ConfigureServices(IServiceCollection services) { services.Configure
<CookiePolicyOptions>(options => { // This lambda determines whether user
consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context =>true; options.MinimumSameSitePolicy =
SameSiteMode.None; });
        //config to identityServer Services services.AddIdentityServer()
.AddDeveloperSigningCredential() .AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetTestUsers())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResource());
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
 在Configure中添加代码 app.UseIdentityServer(); .我们还需要添加一个登陆页面,名为Account.cshtml.
@{ ViewData["Title"] = "Index"; } <h2>Index</h2> @using
mvcWebFirstSolucation.Models; @model LoginVM;<div class="row"> <div class="
col-md-4"> <section> <form method="post" asp-controller="Account" asp-action="
Login" asp-route-returnUrl="@ViewData["returnUrl"]"> <h4>Use a local to log in
.</h4> <hr /> <divclass="from-group"> <label asp-for="UserName"></label> <input
asp-for="UserName" class="form-control"> <span asp-validation-for="UserName"
class="text-danger"></span> </div> <div class="from-group"> <label asp-for="
PassWord"></label> <input asp-for="PassWord" type="password" class="form-control
"> <span asp-validation-for="UserName" class="text-danger"></span> </div> <div
class="from-group"> <button type="submit" class="btn btn-default">log in
</button> </div> </form> </section> </div> </div> @section Scripts { @await
Html.PartialAsync("_ValidationScriptsPartial") }

在控制器中我们写一个构造函数,用于将IdentityServer.Text给我们封装好的对象传过来,这个对象是我们在Config.cs中添加的用户信息,也就是GetClients的返回值,全都在 
TestUserStore 中。其中还有一个提供好的方法,来给我们用,如果验证通过我们直接跳转到了传递过来的ReturnUrl.
public class AccountController : Controller { private readonly TestUserStore
_users;public AccountController(TestUserStore ussotre) { _users = ussotre; }
[HttpGet] [Route("/Account/Login")] public IActionResult Index(string ReturnUrl
=null) { ViewData["returnUrl"] = ReturnUrl; return View(); } private
IActionResult RediretToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl))
{return Redirect(returnUrl); } return
RedirectToAction(nameof(HomeController.Index),"Home"); } [HttpPost] public async
Task<IActionResult> Login(LoginVM vm,string returnUrl = null) { if
(ModelState.IsValid) { ViewData["returnUrl"] = returnUrl; var user =
_users.FindByUsername(vm.UserName);if (user==null) {
ModelState.AddModelError(nameof(LoginVM.UserName),"userName is exists"); } else
{if(_users.ValidateCredentials(vm.UserName, vm.PassWord)) { var props = new
AuthenticationProperties { IsPersistent= true, ExpiresUtc =
DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30)) }; await
Microsoft.AspNetCore.Http .AuthenticationManagerExtensions .SignInAsync(
HttpContext, user.SubjectId, user.Username, props );return
RediretToLocal(returnUrl); } ModelState.AddModelError(nameof(LoginVM.PassWord),"
Wrong Password"); } } return View(); } }
这个时候最基本的服务端已经配置成功了,我们开始配置受保护的客户端吧。


在客户端中我们不需要引入IdentityServer,因为我们只是去请求服务端然后看看cookies有没有在而已,所以我们只需要给受保护的客户端的Api做好安全判断就好.

在受保护的控制器中添加 [Authorize] 标识。然后再Startup.cs中添加安全验证。并且在Configure中use下 
app.UseAuthentication(); 
public void ConfigureServices(IServiceCollection services) {
services.AddAuthentication(options=> { options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme= "oidc"; }).AddCookie("Cookies"
).AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies";
options.Authority= "http://localhost:5000"; options.RequireHttpsMetadata = false
; options.ClientId= "mvc"; options.ClientSecret = "secret"; options.SaveTokens =
true; });
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
在首页中最好遍历下Claims对象,这个是通过OIDC直接给我们返回回来的.(最后另一个客户端也这么干!)
<div> @foreach (var claim in User.Claims) { <dl> <dt>@claim.Type</dt>
<dd>@claim.Value</dd> </dl> } </div>
现在我们启动项目看一下效果吧。

 

 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信