NetCore項目實戰篇04---集成IdentityService4

你們都知道咱們的項目中已有web api,如今能夠正式訪問,不論任何人只要經過輸入對應的api網址就能夠訪問到咱們的api 資源,這樣是很不安全的,咱們需求對當前用戶進行身份驗證,所以咱們在項目中使用IdentityServer4來對受保護資源並實現身份驗證和/或受權,直接開始上代碼,這些代碼直接能夠在你的項目中使用,並跑起來。android

一、  新建一個空的.netcore web項目,並引入IdentityService4的NuGet包。web

二、  在項目中增長一個config.cs文件json

 public class Config
    {
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId="iphone",
                    ClientSecrets = new List<Secret>
                    {
                        new Secret("secret".Sha256())
                    },
                    RefreshTokenExpiration = TokenExpiration.Sliding,
                    AllowOfflineAccess = true,
                    RequireClientSecret = false,
                    AllowedGrantTypes = new List<string>{"sms_suth_code"},
                    AlwaysIncludeUserClaimsInIdToken = true,
                    AllowedScopes = new List<string>
                    {
                        "gateway_api",
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.OfflineAccess,
                    },

                },
                new Client
                {
                    ClientId="android",
                    ClientSecrets = new List<Secret>
                    {
                        new Secret("secret".Sha256())
                    },
                    RefreshTokenExpiration = TokenExpiration.Sliding,
                    AllowOfflineAccess = true,
                    RequireClientSecret = false,
                    AllowedGrantTypes = new List<string>{"sms_auth_code"},
                    AlwaysIncludeUserClaimsInIdToken = true,
                    AllowedScopes = new List<string>
                    {
                        "gateway_api",
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.OfflineAccess,
                    },

                }
            };
        }
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
            };
        }
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("gateway_api","user service")
            };
        }
        
    }

三、在項目中新增類SmsAuthCodeValidator該類主要是實現IdentityServer4組件中的IextensionGrantValidator接口ValidateAsync()的方法,在該方法寫上本身的驗證邏輯,這裏咱們只用戶在登陸時輸入的手機號和驗證碼進行了校驗,固然在校驗時會調用用戶模塊的api,也就是咱們_userService.CheckOrCreate(phone)方法,服務以前如何發現和調用這裏不展開,下節介紹。SmsAuthCodeValidator代碼以下api

public class SmsAuthCodeValidator : IExtensionGrantValidator
    {
        private readonly IAuthCodeService _authCodeService;
        private readonly IUserService _userService;
        public SmsAuthCodeValidator(IAuthCodeService authCodeService, IUserService userService)
        {
            _authCodeService = authCodeService;
            _userService = userService;
        }
        public string GrantType => "sms_auth_code";

        public async Task ValidateAsync(ExtensionGrantValidationContext context)
        {
            var phone = context.Request.Raw["phone"];
            var code = context.Request.Raw["auth_code"];
            var error = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            if(!string.IsNullOrEmpty(phone)&& !string.IsNullOrEmpty(code))
            {
                //用戶檢查
                _authCodeService.Validate(phone, code);
                //用戶註冊
                var userId = await _userService.CheckOrCreate(phone);
                if(userId <=0)
                {
                    context.Result = error;
                    return;
                }

                context.Result = new GrantValidationResult(userId.ToString(), GrantType);
            }
            else
            {
                context.Result = error;

            }

            
        }
    }

四、在SmsAuthCodeValidator類咱們引用了兩個本地的服務,一個是對驗證碼進行校驗的AuthCodeService類,一個是對手機號進行校驗的UserService,也就是在這個類中對用戶服務模塊進行的手機號校驗。現將這兩個代碼的代碼寫上安全

public interface IAuthCodeService
    {
        /// <summary>
        /// 驗證
        /// </summary>
        /// <param name="phone">手機號</param>
        /// <param name="authCone">驗證碼</param>
        /// <returns></returns>
        bool Validate(string phone, string authCone);
    }


public class AuthCodeService : IAuthCodeService
    {
        public bool Validate(string phone, string authCone)
        {
            return true;
        }
    }
public interface IUserService
    {
        /// <summary>
        /// 檢查手機是否註冊,若是沒有就建立
        /// </summary>
        /// <param name="phone"></param>
        Task<int> CheckOrCreate(string phone);
    }

public class UserService : IUserService
    {
        
        public async Task<int> CheckOrCreate(string phone)
        {
          
            return 1;

        }
    }

五、最後咱們須要增長IdentityServer4中間件,並對咱們的服務進行配置服務器

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.AddIdentityServer()
                .AddExtensionGrantValidator<SmsAuthCodeValidator>()
                .AddDeveloperSigningCredential()
                .AddInMemoryClients(Config.GetClients())
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiResources(Config.GetApiResources());
            services.AddSingleton(new HttpClient());
            services.AddScoped<IAuthCodeService, AuthCodeService>()
                .AddScoped<IUserService, UserService>();

            services.AddMvc();
        }

        // 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();
            }
            app.UseIdentityServer();
            app.UseMvc();
        }
    }

五、 生成並啓動該項目,經過postman訪問,需求增長以下六個參數app

 

 

 

六、若是沒有問題的話咱們會獲取到系統反饋給咱們的token值,返回結果以下:框架

{
    "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjlhMjJlN2E3Zjg1ZmY5MjNiMTJmM2Nm
NGZkMGM3YzYzIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1ODg5MjE2MjUsImV4cCI6
MTU4ODkyNTIyNSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDoxMTEwIiwiYXVkIjpb
Imh0dHA6Ly9sb2NhbGhvc3Q6MTExMC9yZXNvdXJjZXMiLCJnYXRld2F5X2FwaSJd
LCJjbGllbnRfaWQiOiJhbmRyb2lkIiwic3ViIjoiMyIsImF1dGhfdGltZSI6MTU4
ODkyMTYyNSwiaWRwIjoibG9jYWwiLCJzY29wZSI6WyJvcGVua
WQiLCJwcm9maWxlIiwiZ2F0ZXdheV9hcGkiLCJvZmZsaW5lX2FjY2VzcyJdLCJhb
XIiOlsic21zX2F1dGhfY29kZSJdfQ.pyEKOe08jiqtg1rgcf0UGO0hmfEhI5a2cIXw
_-YgXdLVceKa14Jhyy8Ezgom3ipNlci5FwmN-p5ro_3ORtzreU0qxhiCzI5kyPgLRP
lOO8cFykYKY4yQOCD_z2LohSxyvAsTPn0B75_iodujGPQAB4Outs9uAjcHXAnxjBkn
DKl6L5uu609ZaugG4X6T2xx0ZDU-VftrrmB-YX5oe6FU70R4jsRLayL8nrM-u-Q_We
UIfY04M91REX9HqneOGyxSDj2Qku22pC68dlIYQNGhBlYUnSqRMkk39Pe9UmjO8dSp
qqBMtHBEwCQn3cMzG7UbP5gB6F2GgTICUBERbxxwRA
", "expires_in": 3600, "token_type": "Bearer", "refresh_token": "f3051fa24cebf7cbfa73b55563a283bb3c15b129c8c5ff732324a653a7c6eff1" }

七、 懷着好奇的心咱們來看看這個access_token的值反饋給咱們的是什麼,其實他就是JWT(Json Web Token),解析成json格式以下iphone

 {
 alg: "RS256",

 kid: "9a22e7a7f85ff923b12f3cf4fd0c7c63",

 typ: "JWT"

}.
{
 nbf: 1588921625,

 exp: 1588925225,

 iss: "http://localhost:1110",

 aud: [
  "http://localhost:1110/resources",

  "gateway_api"

 ],

 client_id: "android",

 sub: "3",

 auth_time: 1588921625,

 idp: "local",

 scope: [
  "openid",

  "profile",

  "gateway_api",

  "offline_access"

 ],

 amr: [
  "sms_auth_code"

 ]

}. 
[signature]

順便學習一下JWT吧:async

       HTTP提供了一套標準的身份驗證框架:服務器能夠用來針對客戶端的請求發送質詢(challenge),客戶端根據質詢提供身份驗證憑證。質詢與應答的工做流程以下:服務器端向客戶端返回401(Unauthorized,未受權)狀態碼,並在WWW-Authenticate頭中添加如何進行驗證的信息,其中至少包含有一種質詢方式。而後客戶端能夠在請求中添加Authorization頭進行驗證,其Value爲身份驗證的憑證信息。

      Bearer認證(也叫作令牌認證)是一種HTTP認證方案,其中包含的安全令牌的叫作Bearer Token。所以Bearer認證的核心是Token。那如何確保Token的安全是重中之重。一種方式是使用Https,另外一種方式就是對Token進行加密簽名。而JWT就是一種比較流行的Token編碼方式。能夠看出JWT有三部分組成:

<header>.<payload>.<signature>

  1. Header:由algtyp組成,alg是algorithm的縮寫,typ是type的縮寫,指定token的類型。該部分使用Base64Url編碼。
  2. Payload:主要用來存儲信息,包含各類聲明,一樣該部分也由BaseURL編碼。
  3. Signature:簽名,使用服務器端的密鑰進行簽名。以確保Token未被篡改。

下一篇咱們將介紹網關,經過網關來訪問咱們的用戶模塊的api資源,並集成IdentityServer4

相關文章
相關標籤/搜索