IdentityServer4實現單點登錄統一認證


 開發環境:

vs2017、net Core 2.1、sqlserver2008、IdentityServer4版本2.4.0。

一、搭建IdentityServer4服務端

打開VS2017,新建 netcore項目:    名字叫:IdentityS4, 然后選擇webMVC這個,如下圖:

引進安裝依賴項:IdentityServer4

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

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

using IdentityServer4;
using IdentityServer4.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace IdentityS4
{
    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


    }

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; } }

 數據庫建立Admin表

/*
Navicat SQL Server Data Transfer

Source Server         : 輕量應用服務器
Source Server Version : 100000
Source Host           : 120.79.21.96 :1433
Source Database       : test
Source Schema         : dbo

Target Server Type    : SQL Server
Target Server Version : 100000
File Encoding         : 65001

Date: 2019-05-22 09:56:13
*/


-- ----------------------------
-- Table structure for Admin
-- ----------------------------
DROP TABLE [dbo].[Admin]
GO
CREATE TABLE [dbo].[Admin] (
[Id] int NOT NULL ,
[CreateDate] datetime NULL ,
[UserName] nvarchar(MAX) NULL ,
[Password ] nvarchar(MAX) NULL ,
[Remark] nvarchar(MAX) NULL 
)


GO

-- ----------------------------
-- Records of Admin
-- ----------------------------
INSERT INTO [dbo].[Admin] ([Id], [CreateDate], [UserName], [Password ], [Remark]) VALUES (N'1', N'2019-05-21 18:05:52.000', N'test', N'123456', N'測試賬號')
GO
GO 

在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=120.79.21.96 ;database=test;user=sa;password=Sa123456;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

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

接下來 我們來做登錄頁面

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityS4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace IdentityS4.Controllers
{

        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服務端的工作完成,粘貼全部代碼即一個重要文件文件代碼(Startup.cs) 主要看擺放位置

Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityS4.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace IdentityS4
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddDbContext<EFContext>(options => options.UseSqlServer(Configuration.GetConnectionString("conn")));//注入DbContext

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

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

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

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

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {

            app.UseIdentityServer();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

  

 

 

接下來我們要開始建客戶端了,也就是需要保護的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認證,這樣就達到了單點登錄統一認證的效果了!

 


免責聲明!

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



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