<六>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

 

 

posted @ 2020-10-26 11:15  许轩霖  阅读(265)  评论(0编辑  收藏  举报