.Net5 WebApi中使用IdentityServer4搭建身份认证中心,以及客户端的身份认证集成,包括token续签(refreshToken)(已在生产中使用)

本文内容:
1、使用IdentityServer4搭建身份认证中心服务端;
2、不同客户端接入到身份认证中心实现身份认证;

话不多说,进入正题:

1、使用IdentityServer4搭建身份认证中心服务端;

a、使用nuget安装IdentityServer4,不做过多赘述

b、在Startup中注入IdentityServer4:

        public void ConfigureServicesMain(IServiceCollection services)
        {
            //跨域
            services.AddLevoxCors(new AddErpInjectOption());
            //控制器
            services.AddControllers();
            //接口文档
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = $"身份认证中心 - {DateTime.Now:yyyy-MM-dd HH:mm:ss dddd}", Version = "v1" });
            });
            //身份认证
            new IdentityServer4Service().Register(services);
        }

IdentityServer4Service服务类:

    public class IdentityServer4Service
    {
        /// <summary>
        /// 将Id4注入到容器   CreateDate:2021-03-29 15:29:10.746  Author:Lingbug
        /// </summary>
        /// <param name="services"></param>
        public void Register(IServiceCollection services)
        {
            //注入
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryIdentityResources(GetIdentityResources())
                .AddInMemoryApiResources(GetApiResources())
                .AddInMemoryApiScopes(GetApiScopes())
                .AddInMemoryClients(FillClients(GetClients()))
                //使用自定义认证逻辑(也就是登录逻辑)
                .AddResourceOwnerValidator<ErpResourceOwnerPasswordValidator>();
        }

        /// <summary>
        /// 获取可以访问的资源   LastUpdateDate:2021-04-15 17:08:33.402  Author:Lingbug
        /// </summary>
        /// <returns></returns>
        private List<IdentityResource> GetIdentityResources() => new()
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };

        /// <summary>
        /// 获取Api集合   CreateDate:2021-03-29 15:17:23.842  Author:Lingbug
        /// </summary>
        /// <returns></returns>
        private List<ApiResource> GetApiResources()
        {
            return new()
            {
                new("ErpApi", "ERP接口")
                {
                    Scopes = new List<string>() { "ErpApiScope" }
                }
            };
        }

        /// <summary>
        /// 获取Scope集合   CreateDate:2021-03-29 15:17:59.323  Author:Lingbug
        /// </summary>
        /// <returns></returns>
        private List<ApiScope> GetApiScopes()
        {
            return new()
            {
                new("ErpApiScope")
            };
        }

        /// <summary>
        /// 获取客户端集合(未做额外处理)   CreateDate:2021-03-29 15:19:06.153  Author:Lingbug
        /// </summary>
        /// <returns></returns>
        private List<Client> GetClients()
        {
            return new()
            {
                new()
                {
                    ClientId = "ErpApi",
                    ClientSecrets = { new Secret("ErpApiSecret") },
                    AllowedScopes = new List<string>
                    {
                        "ErpApiScope",
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.OfflineAccess
                    }
                }
            };
        }

        /// <summary>
        /// 额外处理客户端信息(加密,过期时间,授权类型等)   CreateDate:2021-03-29 15:23:13.429  Author:Lingbug
        /// </summary>
        /// <param name="apiClients"></param>
        /// <returns></returns>
        private List<Client> FillClients(List<Client> apiClients)
        {
            //为空,不操作
            if (apiClients.IsNullOrEmptyList()) return new List<Client>();
            //读取配置
            var tokenExpiredMinuteStr = ConfigurationUtil.GetString("TokenExpiredMinute");
            //过期分钟
            int tokenExpiredMinute = tokenExpiredMinuteStr.IsNullOrWhiteSpaceString()
                ? 60
                : Convert.ToInt32(tokenExpiredMinuteStr);
            //读取配置
            var refreshTokenExpiredHoursStr = ConfigurationUtil.GetString("RefreshTokenExpiredHours");
            //过期小时
            int refreshTokenExpiredHours = tokenExpiredMinuteStr.IsNullOrWhiteSpaceString()
                ? 72
                : Convert.ToInt32(refreshTokenExpiredHoursStr);
            foreach (var apiClient in apiClients)
            {
                //加密
                apiClient.ClientSecrets = apiClient.ClientSecrets.Select(r => new Secret(r.Value.Sha256())).ToList();
                //密码模式
                apiClient.AllowedGrantTypes = GrantTypes.ResourceOwnerPassword;

                //token过期时间
                apiClient.AccessTokenLifetime = tokenExpiredMinute * 60;

                //配置token续签
                ConfigRefreshToken(apiClient, refreshTokenExpiredHours);
            }
            //返回
            return apiClients;
        }

        /// <summary>
        /// 配置token续签   LastUpdateDate:2021-05-07 09:44:46.346  Author:Lingbug
        /// </summary>
        /// <param name="apiClient"></param>
        /// <param name="refreshTokenExpiredHours"></param>
        /// <returns></returns>
        private Client ConfigRefreshToken(Client apiClient, int refreshTokenExpiredHours)
        {
            //开启token续签
            apiClient.AllowOfflineAccess = true;
            //绝对过期
            apiClient.RefreshTokenExpiration = TokenExpiration.Absolute;
            //续签token过期时间
            apiClient.AbsoluteRefreshTokenLifetime = refreshTokenExpiredHours * 60 * 60;
            //返回
            return apiClient;
        }
    }

自定义认证逻辑(登录):

    public class ErpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
    {
        /// <summary>
        /// 登录   LastUpdateDate:2021-03-30 10:00:01.398  Author:Lingbug
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            //登录操作
            var loginResult = await GetLoginUserAsync(context);
            if (loginResult.ErrorMsg.IsNullOrWhiteSpaceString())
            {
                //成功
                context.Result = new GrantValidationResult(JsonConvert.SerializeObject(loginResult.User), OidcConstants.AuthenticationMethods.UserPresenceTest);
            }
            else
            {
                //失败
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, loginResult.ErrorMsg);
            }
        }

        /// <summary>
        /// 登录逻辑   LastUpdateDate:2021-04-12 11:29:56.632  Author:Lingbug
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private async Task<(LoginUserDto User, string ErrorMsg)> GetLoginUserAsync(ResourceOwnerPasswordValidationContext context)
        {
            //sql
            string sql = $@"select * from userInfo where username = '{context.UserName}' and password = '{context.Password}'";
            //查询用户信息
            LoginUserDto user = null;
            //返回
            return (user,null);
        }
    }

b、启用IdentityServer4身份认证:

        public void ConfigureMain(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "身份认证中心 v1"));

            app.UseRouting();

            //跨域
            app.UseCors(ErpInjectExtensions.GetLevoxCorsPolicyName());

            app.UseHttpsRedirection();

            //身份认证
            app.UseIdentityServer();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

ok,身份认证中心(服务端)搭建完毕!

2、不同客户端接入到身份认证中心实现身份认证;

注入身份认证:

    /// <summary>
    /// 身份认证   LastUpdateDate:2021-03-30 09:49:51.414  Author:Lingbug
    /// </summary>
    public static class IdentityServer4AuthorizationExtensions
    {
        /// <summary>
        /// 注入身份认证到容器(使用时,记得在Startup.cs->Configure方法->其中中间件app.UseAuthentication()(在app.UseAuthorization()上一行添加))   LastUpdateDate:2021-03-30 09:45:05.610  Author:Lingbug
        /// </summary>
        /// <param name="services"></param>
        /// <param name="option"></param>
        public static void AddErpAuthorization(this IServiceCollection services, AddErpInjectOption option)
        {
            //token类型
            string tokenType = JwtBearerDefaults.AuthenticationScheme;
            //身份认证中心地址
            string serverUrl = GetIdentityServerUrl(option);
            //是否使用https
            bool isUseHttpsValidate = serverUrl.StartsWith("https://");
            services.AddAuthentication(tokenType).AddJwtBearer(tokenType, options =>
            {
                //赋值
                options.Authority = serverUrl;
                //赋值
                options.RequireHttpsMetadata = isUseHttpsValidate;
                //赋值
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.FromSeconds(5)
                };

                //options.Events = new JwtBearerEvents
                //{
                //    OnMessageReceived = context =>
                //    {
                //        var accessToken = context.Request.Query["access_token"].ToString();
                //        var path = context.HttpContext.Request.Path.ToString();
                //        LoggerTestUtil.SimpleLog("OnMessageReceived", "accessToken:" + accessToken, "path:" + path);
                //        if (!string.IsNullOrEmpty(accessToken) && (path.StartsWith("/levox/testHub")))
                //        {
                //            context.Token = accessToken;
                //        }
                //        return Task.CompletedTask;
                //    }
                //};
            });
        }

        /// <summary>
        /// 获取身份认证中心地址(如果没有传递,则读取配置LevoxFrameworkOption:AuthorizationCenterUrl)   LastUpdateDate:2021-03-31 10:06:04.117  Author:Lingbug
        /// </summary>
        /// <param name="option"></param>
        /// <returns></returns>
        private static string GetIdentityServerUrl(AddErpInjectOption option)
        {
            //为空,读取配置
            if (string.IsNullOrWhiteSpace(option.AuthorizationCenterUrl)) option.AuthorizationCenterUrl = ConfigurationUtil.GetString("AuthorizationCenterUrl");
            //校验
            if (option.AuthorizationCenterUrl.IsNullOrWhiteSpaceString()) throw new Exception("请配置身份认证地址!");
            //记录日志
            LoggerTestUtil.SimpleLog("身份认证地址为:" + option.AuthorizationCenterUrl);
            //返回
            return option.AuthorizationCenterUrl;
        }
    }

启用身份认证:

        /// <summary>
        /// 使用ERP中间件   LastUpdateDate:2021-04-01 09:55:50.710  Author:Lingbug
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="option">配置信息</param>
        public static void UseErpConfiguration(this IApplicationBuilder app, IWebHostEnvironment env, UseErpConfigurationOption option)
        {
            //错误页
            app.UseDeveloperExceptionPage();
            //静态资源
            app.UseErpFileAccess(env, option);

            //swagger
            app.UseSwagger();
            //swagger的json地址
            if (option.SwaggerApiJsonUrl.IsNullOrWhiteSpaceString()) option.SwaggerApiJsonUrl = "/swagger/v1/swagger.json";
            //swagger名称
            if (option.SwaggerApiName.IsNullOrWhiteSpaceString()) option.SwaggerApiName = $"乐薇子系统Api - {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            //使用
            app.UseSwaggerUI(c => c.SwaggerEndpoint(option.SwaggerApiJsonUrl, option.SwaggerApiName));

            //保存依赖注入
            app.SaveContainer();
            //路由
            app.UseRouting();
            //跨域
            app.UseCors(ErpInjectExtensions.GetLevoxCorsPolicyName());
            //https
            app.UseHttpsRedirection();
            //身份认证
            app.UseAuthentication();
            //授权
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                //注入集线器
                endpoints.MapLevoxHubs();
                //控制器
                endpoints.MapControllers();
            });
        }

ok,接入完毕!

Ending~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值