ASP.NET Core分布式项目实战(oauth2 + oidc 实现 server部分)--学习笔记
任务15:oauth2 + oidc 实现 server部分
基于之前快速入门的项目(MvcCookieAuthSample):
https://www.cnblogs.com/MingsonZheng/p/11614686.html
https://www.cnblogs.com/MingsonZheng/p/11623815.html
mvcCookieAuthSample2下载地址:
http://video.jessetalk.cn/course/5/material/217/download
把这个 MVC 注册登录的网站变成一个单点登录,现在它是自己登录自己使用,我们需要把它的登录信息返回给第三方
添加 identityserver4 引用
在 startup 中
using IdentityServer4;
按照之前的文章添加 Config.cs
using System.Collections;
using System.Collections.Generic;
using IdentityServer4.Models;
using IdentityServer4.Test;
namespace mvcCookieAuthSample
{
public class Config
{
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client()
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.Implicit,// 隐式模式
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = {"api"},
}
};
}
public static IEnumerable<ApiResource> GetApiResource()
{
return new List<ApiResource>
{
new ApiResource("api", "My Api")
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
};
}
public static List<TestUser> GetTestUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId = "1",
Username = "mingsonzheng",
Password = "123456"
}
};
}
}
}
startup 的 ConfigureServices
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryClients(Config.GetClients())
.AddInMemoryApiResources(Config.GetApiResource())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddTestUsers(Config.GetTestUsers());
//services.AddDbContext<ApplicationDbContext>(options =>
//{
// options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
//});
//services.AddIdentity<ApplicationUser, ApplicationUserRole>()
// .AddEntityFrameworkStores<ApplicationDbContext>()
// .AddDefaultTokenProviders();
//services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
// .AddCookie(options => {
// options.LoginPath = "/Account/Login";
// });
//services.Configure<IdentityOptions>(options =>
//{
// options.Password.RequireLowercase = true;
// options.Password.RequireNonAlphanumeric = true;
// options.Password.RequireUppercase = true;
// options.Password.RequiredLength = 12;
//});
services.AddMvc();
}
startup 的 Configure 中 UseIdentityServer
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
//app.UseAuthentication();
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
我们已经把 IdentityServer4 添加到 MVC 程序中,接着需要在 Controller 中实现这个逻辑
首先注释 AccountController 原先的登录逻辑
//private UserManager<ApplicationUser> _userManager;
//private SignInManager<ApplicationUser> _signInManager;
Logout 中使用 HttpContext.SignOutAsync 替换
public async Task<IActionResult> Logout()
{
//await _signInManager.SignOutAsync();
await HttpContext.SignOutAsync();
return RedirectToAction("Index", "Home");
}
接着改造登录的逻辑,我们需要验证用户名和密码,前面我们在 Config 中添加了 TestUser,它被放在 TestUserStore 中,可以通过依赖注入引用进来,有了它之后就可以在登录的时候拿到用户名和密码
private readonly TestUserStore _users;
public AccountController(TestUserStore users)
{
_users = users;
}
因为 TestUser 本身不提供 Email 登录,所以我们需要修改 LoginViewModel 以及 Login.cshtml
LoginViewModel
[Required]
//[DataType(DataType.EmailAddress)]
//public string Email { get; set; }
public string UserName { get; set; }
Login.cshtml
<div class="form-group">
<label asp-for="UserName"></label>
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>
改造登录的逻辑
public async Task<IActionResult> Login(LoginViewModel loginViewModel,string returnUrl)
{
if (ModelState.IsValid)
{
//ViewData["ReturnUrl"] = returnUrl;
//var user = await _userManager.FindByEmailAsync(loginViewModel.Email);
//if (user == null)
//{
// ModelState.AddModelError(nameof(loginViewModel.Email), "Email not exists");
//}
//else
//{
// await _signInManager.SignInAsync(user, new AuthenticationProperties { IsPersistent = true });
// return RedirectToLoacl(returnUrl);
//}
ViewData["ReturnUrl"] = returnUrl;
var user = _users.FindByUsername(loginViewModel.UserName);
if (user == null)
{
ModelState.AddModelError(nameof(loginViewModel.UserName), "UserName not exists");
}
else
{
if (_users.ValidateCredentials(loginViewModel.UserName, loginViewModel.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 RedirectToLoacl(returnUrl);
}
ModelState.AddModelError(nameof(loginViewModel.Password), "Wrong Password");
}
}
return View();
}
这样,我们就实现了一个通过 IdentityServer4 下的方法来实现了一个登录逻辑,然后做了一个跳转,下一节再把客户端加进来
课程链接
http://video.jessetalk.cn/course/explore
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。
如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。