zoukankan      html  css  js  c++  java
  • 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) 。

  • 相关阅读:
    Ubuntu配置sublime text 3的c编译环境
    ORA-01078错误举例:SID的大写和小写错误
    linux下多进程的文件拷贝与进程相关的一些基础知识
    ASM(四) 利用Method 组件动态注入方法逻辑
    基于Redis的三种分布式爬虫策略
    Go语言并发编程总结
    POJ2406 Power Strings 【KMP】
    nyoj 会场安排问题
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
    Java的String、StringBuffer和StringBuilder的区别
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/12861761.html
Copyright © 2011-2022 走看看