IdentityServer4實現單點登陸統一認證

  什麼是單點登陸統一認證:假如某公司旗下有10個網站(好比各類管理網站:人事系統啊,財務系統啊,業績系統啊等),我是該公司一管理員或者用戶,按照傳統網站模式是這樣:我打開A網站 輸入帳號密碼 而後進入到A網站辦點事,辦完以後,我有須要到B網站去辦點事,這個時候又須要輸入帳號密碼,假如你還要到C網站辦點事,又再須要輸入帳號密碼。。。。。html

  爲了解決這個問題,因此出現了單點登陸統一認證:即 該改管理員 登陸了其中一個網站獲得了ids4的受權以後,他再登入該公司旗下其餘網站的時候不須要在輸入帳號密碼,可以直接進入後臺辦事! 這就是單點登陸統一認證!
web

本文章目的:sql

使用IdentityServer4作一個單點登陸統一認證的例子。我會用最簡潔的代碼和最能讓新手懂的方式,來完成這個例子,不會像官方例子同樣讓新手看起來很吃力,由於我本身就體驗過那種感受^_^數據庫

1.用戶訪問一個MVC網站 A,A網站發現用戶沒有登陸受權,而後跳轉到ids4服務去登陸json

2.若是用戶在ids4的登陸頁面上輸入了正確的帳號密碼(從數據庫某個用戶表驗證),則跳轉回A網站,而後A網站就能夠顯示相關的內容服務器

 有興趣愛好一塊兒學習交流netcore相關技術的加羣:275080612.另外本人博客:小彪博客  歡迎來交流!mvc

前言:app

  博主爲了研究ids4,把官方文檔斷斷續續看了幾遍,還有網上的不少大神文章都看了下,一句話,看的很累!一直沒有找到這麼純粹又實用的例子,通過千難萬苦的研究,終於有點成果,如今我決心把這些東西試着以最簡單的方式寫出來給你們參考,即便你是菜鳥跟着個人步驟來 你也能作出來!大神就忽略哈,若有指教或者建議,請留言! 框架

開發環境:

vs2017 、net Core 2.一、sqlserver2012 async

一。搭建IdentityServer4服務端

打開VS2017,新建 netcore項目:    名字叫:IdentityS4, 而後選擇webMVC這個,以下圖:

 

引進安裝依賴項:IdentityServer4

 

設置該項目的地址爲:http://localhost:5000

 

新建一個配置文件類:Config.cs  代碼以下:

public class Config
    {
        // scopes define the resources in your system
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
            };
        }

        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                // OpenID Connect隱式流客戶端(MVC)
                new Client
                {
                    ClientId = "mvc",
                    ClientName = "MVC Client",
                    AllowedGrantTypes = GrantTypes.Implicit,//隱式方式
                    RequireConsent=false,//若是不須要顯示否贊成受權 頁面 這裏就設置爲false
                    RedirectUris = { "http://localhost:5002/signin-oidc" },//登陸成功後返回的客戶端地址
                    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },//註銷登陸後返回的客戶端地址

                    AllowedScopes =//下面這兩個必需要加吧 不太明白啥意思
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile
                    }
                }
            };
        }
    }

 

在Startup.cs的ConfigureServices方法中注入Ids4服務,以下面紅色部分代碼:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddIdentityServer()//Ids4服務
                .AddDeveloperSigningCredential()
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryClients(Config.GetClients());//把配置文件的Client配置資源放到內存

        }

 

在Startup.cs的Configure方法中添加ids4服務中間件(注意要放在UseMvc以前就能夠):

app.UseIdentityServer();

 

如今ids4自己的基本的配置弄好了,下面咱們要開始弄跟數據庫相關的東西了,你們想一想,既然要登陸,那確定須要鏈接數據庫而且讀取出其中的用戶信息去驗證,好比帳號、密碼。好的,那咱們就按照下面一步一步來作

添加DbContext類 名字叫:EFContext.cs ,代碼以下(其中紅色部分是咱們待會須要添加的實體類,也就是對應數據庫裏面的用戶表Admin):

public class EFContext : DbContext
    {
        public EFContext(DbContextOptions<EFContext> options) : base(options)
        {

        }

        #region 實體集

        public DbSet<Admin> Admin { get; set; }//注意 這裏這個Admin不能寫成Admins不然會報錯找不到Admins 由於咱們如今數據庫和表是現成的 這裏就至關於實體對應的數據庫是Admin

        #endregion
    }

 

添加一個Admin.cs的實體類,對應數據庫裏面的用戶表Admin (而後把這個實體類添加到上一步的EFContext中,也就是上一步代碼的紅色部分)

public class Admin
    {
        public int Id { get; set; }
        public DateTime CreateDate { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Remark { get; set; }
    }

 

在Startup.cs的ConfigureServices方法中注入 EFContext,以下面紅色部分代碼:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<EFContext>(options=>options.UseSqlServer(Configuration.GetConnectionString("conn")));//注入DbContext
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddIdentityServer()//Ids4服務 .AddDeveloperSigningCredential() .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryClients(Config.GetClients());//把配置文件的Client配置資源放到內存 }

 

接下來,咱們就要寫Admin這個實體類跟數據庫打交道的代碼了,好比增刪改查啊,在net中通常交DAL層,在netCore中 通常交services層,要注意的是 netcore的框架是IOC的框架,依賴注入的,因此這個services層須要接口的形式!

新建一個接口:IAdminService.cs 代碼以下:

public interface IAdminService
    {
        Task<Admin> GetByStr(string username, string pwd);//根據用戶名和密碼查找用戶
    }

新建實現該接口的類AdminService.cs

public class AdminService:IAdminService
    {
        public EFContext db;
        public AdminService(EFContext _efContext)
        {
            db = _efContext;
        }
        /// <summary>
        /// 驗證用戶,成功則返回用戶信息,不然返回null
        /// </summary>
        /// <param name="username"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public async Task<Admin> GetByStr(string username, string pwd)
        {
            Admin m=await db.Admin.Where(a => a.UserName == username && a.Password == pwd).SingleOrDefaultAsync();
            if (m!=null)
            {
                return m;
            }
            else
            {
                return null;
            }
        }
    }    

 

在Startup.cs的ConfigureServices方法中注入 service層,以下面紅色部分代碼:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<EFContext>(options=>options.UseSqlServer(Configuration.GetConnectionString("conn")));//注入DbContext
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddIdentityServer()//Ids4服務
                .AddDeveloperSigningCredential()
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryClients(Config.GetClients());//把配置文件的Client配置資源放到內存

            services.AddTransient<IAdminService,AdminService>();//service注入
        }

 

在配置文件appsettings.json中添加數據庫鏈接字符串以下紅色部分代碼:

{
  "ConnectionStrings": { "conn": "server=.;database=blogcore;uid=sa;pwd=123" }, 
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

 

至此,應該是能夠正確的鏈接數據庫的,你們能夠去Home控制器中查詢點數據測試下顯示到首頁,保證能鏈接數據庫成功的查詢出數據就能夠。

接下來 咱們來作登陸頁面

新增一個控制器AccountController,代碼以下:

public class AccountController : Controller
    {
        private IAdminService _adminService;//本身寫的操做數據庫Admin表的service
        private readonly IIdentityServerInteractionService _interaction;
        private readonly IClientStore _clientStore;
        private readonly IAuthenticationSchemeProvider _schemeProvider;
        private readonly IEventService _events;
        public AccountController(IIdentityServerInteractionService interaction,
            IClientStore clientStore,
            IAuthenticationSchemeProvider schemeProvider,
            IEventService events,
            IAdminService adminService)
        {
            _interaction = interaction;
            _clientStore = clientStore;
            _schemeProvider = schemeProvider;
            _events = events;
            _adminService = adminService;
        }

        /// <summary>
        /// 登陸頁面
        /// </summary>
        [HttpGet]
        public async Task<IActionResult> Login(string returnUrl=null)
        {
            ViewData["returnUrl"] = returnUrl;
            return View();
        }

        /// <summary>
        /// 登陸post回發處理
        /// </summary>
        [HttpPost]
        public async Task<IActionResult> Login(string userName, string password,string returnUrl=null)
        {
            ViewData["returnUrl"] = returnUrl;
            Admin user = await _adminService.GetByStr(userName, password);
            if (user!=null)
            {
                AuthenticationProperties props= new AuthenticationProperties
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1))
                };
                await HttpContext.SignInAsync(user.Id.ToString(), user.UserName, props);
                if (returnUrl!=null)
                {
                    return Redirect(returnUrl);
                }

                return View();
            }
            else
            {
                return View();
            }
        }
    }

 

添加登陸view視圖,代碼以下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Login</title>
</head>
<body>

    <div align="center">
        <h1>統一認證登陸中心</h1>
        <form action="/Account/Login" method="post">
            用戶名:<input type="text" name="userName" /><br />
            密 碼:<input type="password" name="password" /><input type="hidden" name="returnUrl" value="@ViewData["returnUrl"]" /> <br />
            <input type="submit" value="登陸" />
        </form>
    </div>
</body>
</html>

 

至此,IdentityServer4服務端的工做完成,接下來咱們要開始建客戶端了,也就是須要保護的MVC網站

 

二。搭建客戶端

新建一個名爲 MvcClient 的

 

把地址設置爲:http://localhost:5002

 

在Startup.cs的ConfigureServices方法中添加以下紅色部分代碼(主要用來配置認證中心ids4的及本身做爲客戶端的認證信息):

public void ConfigureServices(IServiceCollection services)
        {
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(options =>
                {
                    options.DefaultScheme = "Cookies";
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie("Cookies")
                .AddOpenIdConnect("oidc", options =>
                {
                    options.SignInScheme = "Cookies";

                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;

                    options.ClientId = "mvc";
                    options.SaveTokens = true; });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

在 Configure方法中添加這行代碼(須要在UseMvc以前就能夠):

app.UseAuthentication();

 

到此,客戶端跟統一認證的信息就配置完了。接下來咱們把Home控制器上面加上須要驗證的標誌:[Authorize]

 

咱們把默認的Index視圖頁面html代碼去掉,改爲以下(主要用來顯示下受權後拿到的用戶信息):

@{
    ViewData["Title"] = "Home Page";
}

<div align="center"><h1>這裏是受保護的客戶端首頁</h1></div>
<h3>User claims</h3>

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>

    }
</dl>

 

 

到此,客戶端的工做也作完了,下面咱們要開始啓動項目了

 

設置項目爲多項目啓動:解決方案上右鍵-屬性

 

如今咱們啓動項目:服務器項目和 客戶端都運行了,可是客戶端會直接跳轉到服務端登陸頁面

服務端

 

客戶端(5002)跳轉過來的登陸頁面:

 

 

而後輸入正確帳號密碼 點擊登陸認證經過以後就跳轉回 客戶端網站去了

 

至此 ,例子結束!

從這個例子中,我們能夠再加幾個客戶端網站,而後統一到這個ids4認證,這樣就達到了單點登陸統一認證的效果了!

源碼下載:https://pan.baidu.com/s/1HRiAF7LMinCh03AZNArfcQ

相關文章
相關標籤/搜索