<六>OIDC 客户端的引用服务端登录页面的实现
上一节服务端已经弄好了,那么我们来创建一个mvc客户端,访问客户端的时候直接调用服务端的登录页面实现登录。
1、创建一个mvcclient, 端口默认为5004。
startup类中的 ConfigureServices函数总中加入认证配置
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:5003";//identity服务器域名 options.RequireHttpsMetadata = false; //没有证书啥的不需要传 options.ClientId = "myself"; //MVC服务端配置的clientId options.ClientSecret = "secret"; options.SaveTokens = true; }); services.AddControllersWithViews(); }
config中加入
app.UseAuthentication();
app.UseAuthorization();
默认的Homecontroller上面加上认证特性[Authorize]
这样客户端的配置就可以了。
2、修改一下服务端的代码
2.1、修改login前端,新增接收回调链接的参数
@{ ViewData["Title"] = "登录"; } <h2 style="text-align:center">登录管理系统</h2> <hr /> <div> <form asp-controller="Account" asp-action="Login" method="post"> <div> <label class="control-label">用户名</label> <input class="form-control" type="text" name="username" /> </div> <div> <label class="control-label">密码</label> <input class="form-control" type="password" name="password" /> </div> <div class="form-group"> <input type="submit" value="登录" class="btn btn-primary" /> </div> <input type="text" class="form-control" id="returnUrl" name="returnUrl" value="@ViewData["Rurl"]" /> </form> </div>
2.2、修改controller中的登录逻辑
public class AccountController : Controller { private readonly TestUserStore _testUserStore; public AccountController( TestUserStore testUserStore) { _testUserStore = testUserStore; } public IActionResult Index() { return View(); } public IActionResult Login(string returnUrl = "/Home/Index") { ViewData["Rurl"] = returnUrl; return View(); } /// <summary> /// post 登录请求 /// </summary> /// <returns></returns> [HttpPost] public async Task<IActionResult> Login(string userName, string password,string returnUrl) { if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)) { return Json(new { result = false, msg = "用户名或者密码不能为空!" }); } var user = _testUserStore.FindByUsername(userName); if (user == null) { return Json(new { result = false, msg = "用户不存在!" }); } if (_testUserStore.ValidateCredentials(userName, password)) { var props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(3)) }; await AuthenticationManagerExtensions.SignInAsync( HttpContext, new IdentityServerUser(user.SubjectId), props ); return Redirect(returnUrl); } return Json(new { result = false, msg = "用户名密码错误!" }); } }
2.3、修改identity 中的配置 config.cs
public static class Config { public static IEnumerable<ApiScope> GetScopes() { return new ApiScope[] { new ApiScope("api1scope"), new ApiScope("api2scope"), //new ApiScope("scope2"), }; } // 这个 Authorization Server 保护了哪些 API (资源) public static IEnumerable<ApiResource> GetApiResources() { return new[] { new ApiResource("api", "My API") { Scopes = { "api1scope", "api2scope" } } }; } public static IEnumerable<IdentityResource> GetIdentityResources() { return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Email(), }; } // 哪些客户端 Client(应用) 可以使用这个 Authorization Server public static IEnumerable<Client> GetClients() { return new[] { new Client { ClientId = "myself",//定义客户端 Id ClientSecrets = new [] { new Secret("secret".Sha256()) },//Client用来获取token AllowedGrantTypes = GrantTypes.Implicit,//隐式流程 RequireConsent=false, RedirectUris={"http://localhost:5004/signin-oidc"},//这个在identity的地址中是固定的,登录成功回调处理地址,处理回调返回的数据 PostLogoutRedirectUris = { "http://localhost:5004/signout-callback-oidc" },//退出的时候会返回到这个地址 AllowedScopes = { IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.OpenId, }// 允许访问的 API 资源 } }; } //测试用户 public static IEnumerable<TestUser> GetUsers() { return new[] { new TestUser { SubjectId = "1", Username = "myname", Password = "password" } }; } }
2.4、在服务端startup中引用配置
public void ConfigureServices(IServiceCollection services) { services.AddIdentityServer().AddDeveloperSigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryApiScopes(Config.GetScopes()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers().ToList()) .AddInMemoryIdentityResources(Config.GetIdentityResources()); services.AddControllersWithViews(); }
3、运行服务端和客户端,浏览器访问localhost:5004 就会跳到登录页面,如下图所示,这里我把returnurl给显示出来了。
4、输入用户名和密码,即使服务端config.cs里面TestUser配置的用户名和密码登录后就自动跳转到client 端口5004的主页面
异常1、 如果客户端没有加上 app.UseAuthentication(); 的话会报signin-oidc 的页面404的情况,也就说明了UseAuthentication会自动去解析cookie中的认证数据
异常二:AddDeveloperSigningCredential()这个是开发的签名凭据,只能在开发使用,部署时需要更换。。这里一定要加上,不然会报No signing credential is configured 的错误。
异常三:登录时用户登录之后,无法跳转回原网页,还是停留在登录页。查看信息报错 user is not Authenticated 。解决方案:使用https