IdentityServer4服務器配置


Session認證和JWT(Json Web Token)   

Token認證就是基於JWT

1.Session認證

1. 用戶輸入其登錄信息

2. 服務器驗證信息是否正確,並創建一個session,然后將其存儲在數據庫中

3. 服務器為用戶生成一個sessionId,將具有sesssionId的Cookie將放置在用戶瀏覽器中

4. 在后續請求中,會根據數據庫驗證sessionID,如果有效,則接受請求

5. 一旦用戶注銷應用程序,會話將在客戶端和服務器端都被銷毀

 

2.JWT認證

1. 用戶輸入其登錄信息

2. 服務器驗證信息是否正確,並返回已簽名的token

3. token儲在客戶端,例如存在local storage或cookie中

4. 之后的HTTP請求都將token添加到請求頭里

5. 服務器解碼JWT,並且如果令牌有效,則接受請求

6. 一旦用戶注銷,令牌將在客戶端被銷毀,不需要與服務器進行交互一個關鍵是,令牌是無狀態的。后端服務器不需要保存令牌或當前session的記錄。

JWT里面只存放了一些不敏感的信息    比如一些重要的信息是用戶發起請求 驗證身份成功  再去 ProfileService 中把敏感信息放到HttpContext中   比如租戶ID 等

 

服務器不保存生成Token   Token由三部分組成   根據客戶端請求的Token  根據Token的前部和中部和密鑰計算出來跟尾部相同 就驗證通過  節約了服務器內存

 

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

用VS 直接運行就報錯  但是用VS Core打開 用dotnet run命令運行就沒有報這個錯誤

IdentityServer4配置成功后  配置頁面 localhost:xxxx/.well-known/openid-configuration    

 

 

身份驗證服務器需要添加IdentityServer4 包

客戶端只需要添加IdentityServer4.AccessTokenValidation 包

 

進銷存用的是密碼模式

相當於經銷存和protal    protal是身份驗證服務器  

經銷存只是一個客戶端  只需要添加IdentityServer4.AccessTokenValidation 

 

 

 

1.用戶在第三方客戶端上操作的時候   想要訪問接口地址       先去授權服務器認證

2.授權服務器通過驗證后 會通過ProfileService  把用戶信息包裝成一個Claim 放返回 

3.請求會加上返回的Claim  里面有用戶信息 資料  token

 

注:如果是通過Postman測試  下面這樣傳參沒問題      如果是通過前端來獲取token   會報錯400 Bad Request

都是post接口   通過抓包軟件分析   傳遞的參數是

 

 在前端需要對參數進行格式化   轉成字符串  然后把Content-type改成application/x-www-form-urlencoded

    var param = '';
    let data = {
      client_id:'Consoleclient',
      client_secret:'511536EF-F270-4058-80CA-1C89C192F69A',
      grant_type:'client_credentials'
    };
    for (let property in data) {
      param += `&${property}=${data[property]}`
    }
    param = param.substring(1, param.length)
    this.apiService.identityLoginAPI(param).then(res => {

 

 

Claim是用戶身份  一個用戶可以有多個身份

Scope是API資源的權限  

1.客戶端模式

進銷存前端需要調用后端API  需要先到protal 的IdentityServer服務器  經過授權  拿到token   才能訪問到后端API

  獲取token 傳參方式

  

 

2.密碼模式

  需要輸入真實賬戶和密碼    這種模式body 可以設置為form-data 也可以設置為x-www-form-urlencoded

3.授權碼模式

  做一個統一的登陸界面  比如Pc端在Web上進行QQ登陸    然后比如登陸斗魚的時候  可以用QQ賬號密碼登陸  也會跳轉到QQ登陸的統一界面

 

 

搭建身份驗證服務器

.Net Core的項目模版生成出來后 默認是https訪問  在properties中的launchSettings.json中把sslport改為0

    "iisExpress": {
      "applicationUrl": "http://localhost:5000",
      "sslPort": 0
    }

 

1.新建一個空web Api項目   

  添加IdentityServer4包   這里用的版本都是2.1

  添加Config.cs配置類信息

  這是客戶端模式配置

  

    public class Config
    {
        /// <summary>
        /// 配置資源服務器
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetResource()
        {
            return new List<ApiResource>
            {
                new ApiResource("api","My Api")
            };
        }
        /// <summary>
        /// 配置客戶端
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client()
                {
                    ClientId = "client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets ={
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "api"}
                }
            };
        }
    }

2.把IdentityServer添加到依賴注入配置項

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer()
          //添加開發證書 .AddDeveloperSigningCredential()
          //添加資源Api .AddInMemoryApiResources(Config.GetResource())
          //添加客戶端 .AddInMemoryClients(Config.GetClients()); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }

 

3.在管道中添加身份驗證服務器中間件

            app.UseIdentityServer();

 4.啟動的時候可能會報錯   第一次配報錯  第二次配沒有報錯 如果報錯用Vs Code 打開  用dotnet run 命令運行

進入http://localhost:5000/.well-known/openid-configuration查看配置

"token_endpoint":"http://localhost:5000/connect/token",  這個地址就是獲取token的地址

 

到這里  身份驗證服務器搭建完畢      后面開始搭建客戶端服務器  也就是接口服務器

1.新建一個Web Mvc空項目

  添加IdentityServer4.AccessTokenValidation包

  注入是身份驗證服務器  這里的地址就是上面配的驗證服務器地址

            services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(Options =>
                {
                    Options.Authority = "http://localhost:5000";
                    Options.RequireHttpsMetadata = false;
                    Options.ApiName = "api";

                });

2.在管道中開啟授權驗證中間件

 app.UseAuthentication();

3.在需要保護的接口上添加[Authorize]特性

4.直接訪問現在的接口 就會報錯401  沒有授權

先通過http://localhost:5000/connect/token 身份驗證服務器拿到token 再去訪問api接口

 

第二種 帳號密碼模式

修改驗證服務器的Config.cs

    public class Config
    {
        public static IEnumerable<ApiResource> GetResource()
        {
            return new List<ApiResource>
            {
                new ApiResource("api","My Api")
            };
        }


        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                //客戶端模式
                new Client()
                {
                    ClientId = "client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets ={
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "api"}
                },
                //賬號密碼模式
                new Client()
                {
                    ClientId = "pwdClient",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    ClientSecrets ={
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "api"}
                }
            };
        }
        /// <summary>
        /// 添加一個模擬的帳號密碼
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser>{
                new TestUser{
                    SubjectId = "1",
                    Username="jcb",
                    Password = "123456"
                }
            };
        }
    }

2.把賬號密碼模式也進行注入  修改Startup.cs

            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(Config.GetResource())
                .AddInMemoryClients(Config.GetClients())
                .AddTestUsers(Config.GetTestUsers());

 

這樣就完成了帳號密碼模式的配置

 

把賬號密碼模式改為動態的  通過數據庫進行匹配  

1.新增登錄驗證器類LoginValidator   繼承IResourceOwnerPasswordValidator     接口有一個驗證方法ValidateAsync

    public class LoginValidator : IResourceOwnerPasswordValidator
    {
        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            Customers customers = new Customers() { Name = context.UserName };
            var res = await Login(customers);
            if (res != null)
            {
                //GrantValidationResult實例根據構造函數傳參不同來進行判斷是否成功
                context.Result = new GrantValidationResult(res.Id.ToString(), "password", (IEnumerable<Claim>)null, "local", (Dictionary<string, object>)null);
            }
            else
            {
            }
        }
      //登錄驗證可以寫這里
public async Task<Customers> Login(Customers customer) { using (MyDbContext db = new MyDbContext()) { var res = db.customers.FirstOrDefault(t=>t.Name == customer.Name); if (res != null) { return res; } return null; } } }

2.在注冊身份驗證服務器的時候  把這個登錄驗證添加進來

.AddResourceOwnerValidator<LoginValidator>();

3.這樣子執行的時候 默認會使用自帶的DefaultProfileService  執行到內部IsActiveAsync()方法會報錯     這個類在C:\Users\jiangchengbiao\.nuget\packages\identityserver4\2.1.0\lib\netstandard2.0\IdentityServer4.dll

解決方式:需要新建一個類 繼承IProfileService  重寫里面的IsActiveAsync()   然后再把這個注冊到身份驗證服務器上

    public class ProfileService : IProfileService
    {
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            //通過第一次驗證輸出的賬號密碼 查詢到租戶ID等其他信息   添加到身份信息中
            List<Claim> claims = Enumerable.ToList<Claim>(context.Subject.Claims);
            claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "蔣承標"));
            claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "浙江工貿"));
            claims.Add(new Claim("http://jcb.org/identity/claims/tenantId", "租戶ID"));
            context.IssuedClaims = claims;
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            context.IsActive = true;
            int num = await(Task<int>) Task.FromResult<int>(0);
        }
    }

 

4.把重寫的ProfileService 注冊到身份驗證服務器上

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(Config.GetResource())
                .AddInMemoryClients(Config.GetClients())
                .AddTestUsers(Config.GetTestUsers())
                .AddProfileService<ProfileService>()
                .AddResourceOwnerValidator<LoginValidator>();

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

 到這里就完成了  可以根據輸入的帳號密碼到數據庫進行比對

 

然后在客戶端(也就是經銷商系統)啟動JWT中間件   參數一定要是這個  還沒具體去看

            app.UseJwtTokenMiddleware("IdentityBearer");

    ctx.AuthenticateAsync會去身份驗證服務器中把  各種身份信息查詢出來  這里面有租戶ID  用戶姓名等 放到HttpContext中

    public static class JwtTokenMiddleware
    {
        public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string schema = JwtBearerDefaults.AuthenticationScheme)
        {
            return app.Use(async (ctx, next) =>
            {
                if (ctx.User.Identity?.IsAuthenticated != true)
                {
                    var result = await ctx.AuthenticateAsync(schema);
                    if (result.Succeeded && result.Principal != null)
                    {
                        ctx.User = result.Principal;
                    }
                }

                await next();
            });
        }
    }

 

 

授權碼模式

1.比如登錄斗魚,選擇QQ登錄,跳轉到QQ統一登錄頁面並攜帶returnUrl

2.輸入賬號密碼,同意授權,頁面會回到returnUrl並攜帶Authorization Core

3.斗魚向自己的服務發起登錄請求傳入Authorization Core

4.斗魚后台服務通過Authorization Core參數向QQ發起獲取AccessToken

5.獲取AccessToken后,在向QQ發起獲取用戶信息

6.通過QQ返回的用戶信息創建斗魚賬號,創建斗魚服務頒發的Token返回給瀏覽器

第4-6步都是在后台完成的

 

open id connect

在授權碼模式的第2步,QQ在返回的時候會直接返回用戶信息和Access token,免去了后面的環節

 

 

 

使用OpenID Connect添加用戶認證

1.客戶端安裝Nuget包

IdentityServer4.AccessTokenValidation

Microsoft.AspNetCore.Authentication.Abstractions

Microsoft.AspNetCore.Authentication.Cookies

Microsoft.AspNetCore.Authentication.OpenIdConnect

 

客戶端代碼

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<SchoolDbContext>(d=>d.UseSqlServer(Configuration.GetConnectionString("Default")));

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

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

            services.AddMvc();
        }

 


免責聲明!

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



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