使用IdentityServer4簡單的實現一個SSO登錄


一.簡介

本文使用 ASP.NET Core +IdentityServer4來實現SSO單點登錄(注銷沒有實現),我們其中使用Implicit模式和OIDC協議來實現功能,這里先記錄實現核心代碼,然后再來記錄IdentityServer幫我們做了什么(從請求的流程來訴說)。

二.預備工作

建立 ASP.NET Core 三個項目,分別是Client_IdentityServerClient2_IdentityServerIdentityServer_SSO

然后修改Window的host文件,注冊三個站點,分別是a.cn  b.net  c.cn
在這里插入圖片描述
然后設置三個項目的啟動地址,讓三個項目地址分別對應上面的三個站點,我這里設置兩個客戶端分別是 www.a.cn 和 www.b.net ,服務端為 www.c.cn

舉例

在這里插入圖片描述
在這里插入圖片描述依次按照這種方式來修改剩下的兩個項目啟動地址就可以了。

服務端配置

然后在服務端點開NuGet管理包搜索IdentityServer4進行下載
在這里插入圖片描述

新建一個Config類 ,用來配置IdentityServer4.

    public class config
    {
        public static IEnumerable<ApiResource> GetApiResource()
        {
            return new List<ApiResource>()
            {
                new ApiResource("api","this is api")
            };
        }
        
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>()
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Phone()
            };
        }

         public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser>{
              new TestUser()
              {
                    SubjectId="123",
                    Username="Mr.wen",
                    Password="123465",
                    Claims=new Claim[]
                    {
                        new Claim(ClaimTypes.Role,"管理員")
                    }
              },
              new TestUser()
              {
                    SubjectId="456",
                    Username="123",
                    Password="123456",
                    Claims=new Claim[]
                    {
                        new Claim(ClaimTypes.Role,"閱覽者")
                    }
                    
              }
            };
        }
        
         public static IEnumerable<Client> GetClients()
        {
            return new List<Client>()
            {
                new Client()
                {
                    ClientId="mvc_imp",
                    ClientName="Mvc_Name",        
                    AllowedGrantTypes=GrantTypes.Implicit, 
                    設置是否要授權
                    //RequireConsent=false,
                    
                    //指定允許令牌或授權碼返回的地址(URL)
                    RedirectUris={ "http://www.b.net:5001/signin-oidc","http://www.a.cn:5002/signin-oidc" },
                    //指定允許注銷后返回的地址(URL),這里寫兩個客戶端
                    PostLogoutRedirectUris={ "http://www.b.net:5001/signout-callback-oidc","http://www.a.cn:5002/signout-callback-oidc" },
                    ClientSecrets={new Secret("secret".Sha256())},
                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                    }, 
                }
             };
         }

接下來配置服務端的Startup.cs的Configure和ConfigureServices方法

public void ConfigureServices(IServiceCollection services)
  {
       services.AddIdentityServer(option=>
       {
           //可以通過此設置來指定登錄路徑,默認的登陸路徑是/account/login
           option.UserInteraction.LoginUrl = "/account/login";
                
       })
       .AddDeveloperSigningCredential()
       .AddInMemoryApiResources(Config.GetApiResource())
       .AddInMemoryClients(Config.GetClients())
       .AddInMemoryIdentityResources(Config.GetIdentityResources())
       .AddTestUsers(Config.GetTestUsers());
         
         services.AddMvc();
  }
   
       
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
      if (env.IsDevelopment())
      {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
      }
      else
      {
           app.UseExceptionHandler("/Home/Error");
      }
      
       app.UseIdentityServer();
        
       app.UseStaticFiles();
         
       app.UseMvc(routes =>
       {
               routes.MapRoute(
                  name: "default",
                  template: "{controller=Home}/{action=Index}/{id?}"
                );
       });
 }
       

客戶端配置

配置Startup.cs文件

 public void ConfigureServices(IServiceCollection services)
 {  
            //DefaultChallengeScheme的名字要和下面AddOpenIdConnect方法第一個參數名字保持一致
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
           .AddCookie("Cookies")
           .AddOpenIdConnect("oidc", options =>
           {
               options.Authority = "http://www.c.cn:5000";
               options.RequireHttpsMetadata = false;
               
               //指定允許服務端返回的地址,默認是new PathString("/signin-oidc")
               //如果這里地址進行了自定義,那么服務端也要進行修改
               options.CallbackPath = new PathString("/signin-oidc");
               
               //指定用戶注銷后,服務端可以調用客戶端注銷的地址,默認是new PathString("signout-callback-oidc")
               options.SignedOutCallbackPath = new PathString("/signout-callback-oidc");     
                
               options.ClientId = "mvc_imp";
               options.ClientSecret = "secret";
           });
          services.AddMvc();
 }
        
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
      if (env.IsDevelopment())
      {
           app.UseBrowserLink();
           app.UseDeveloperExceptionPage();
      }
     else
     {
         app.UseExceptionHandler("/Home/Error");
     }
     app.UseAuthentication();
     
     app.UseStaticFiles();
    
     app.UseMvc(routes =>
     {
        routes.MapRoute(
           name: "default",
           template: "{controller=Home}/{action=Index}/{id?}"
        );
     });
}

 

到這里,總的配置就配好了,接下來是主要實現代碼

服務端

建立AccountController控制器,其中有login方法,在login方法里寫我們登錄的邏輯

       [HttpPost]
       public async Task<IActionResult> Login(LoginInputModel model)
       {
            //當登錄提交給后台的model為null,則返回錯誤信息給前台
            if (model == null)
            {
                //這里我只是簡單處理了
                return View();
            }
            //這里同理,當信息不完整的時候,返回錯誤信息給前台
            if (string.IsNullOrEmpty(model.Username) || string.IsNullOrEmpty(model.Password))
            {
                //這里只是簡單處理了
                return View();
            }
            
            //model.Username == "123" && model.Password == "123456"
            //if里面的是驗證賬號密碼,可以用自定義的驗證,
            //我這里使用的是TestUserStore的的驗證方法,
            if (_users.FindByUsername(model.Username)!=null&&_users.ValidateCredentials(model.Username,model.Password))
            {
                   var user = _users.FindByUsername(model.Username);
                //配置Cookie
                AuthenticationProperties properties = new AuthenticationProperties()
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30))
                };
                
                //使用IdentityServer的SignInAsync來進行注冊Cookie
                await HttpContext.SignInAsync(user.SubjectId, model.Username);
                
                //使用IIdentityServerInteractionService的IsValidReturnUrl來驗證ReturnUrl是否有問題
                if (_interaction.IsValidReturnUrl(model.ReturnUrl))
                {
                    return Redirect(model.ReturnUrl);
                }
                return View();
             }
             return View();
        }

客戶端

客戶端的代碼很簡單,即想要驗證的方法或控制器添加一個Authorize特性就可以了

       [Authorize]
        public IActionResult About()
        {
             ViewData["Message"] = "Your application description page.";
             return View();
        }

 

到這里,客戶端和服務端的核心代碼基本結束了,如果想要看程序的UI,或者想要看完整的后台,可以查看我的GitHub

https://github.com/MDZZ3/Identity_SSO

參考

https://www.cnblogs.com/RainingNight/p/oidc-authentication-in-asp-net-core.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM