Example #1
0
        public async Task <(string ClientId, string PlainSecret)> CreateAsync(ClientNewDto model)
        {
            if (await _clientRepo.IsExistedAsync(model.ClientUri))
            {
                throw new IamException(HttpStatusCode.BadRequest, "该客户端地址已经存在!");
            }

            ICollection <string> allowedCorsOrigins = null;

            if (model.AllowedCorsOrigins != null)
            {
                allowedCorsOrigins = model.AllowedCorsOrigins.Split(",", StringSplitOptions.RemoveEmptyEntries);
                foreach (var itm in allowedCorsOrigins)
                {
                    if (!itm.IsUrl())
                    {
                        throw new IamException(HttpStatusCode.BadRequest, $"{itm} 并不是合法的允许的跨域地址,必须是 Url 形式");
                    }
                }
            }

            model.ClientName = model.ClientName.Trim();
            var allowedScopes = model.AllowedScopes?.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(sp => sp.Trim()).ToList() ?? new List <string>();

            // 排除 id scopes 以及 已经存在的 api scopes
            var newScopes = allowedScopes.Except(await _clientRepo.GetIdentityResourceNamesAsync(allowedScopes))
                            .Except(await _clientRepo.GetApiResourceNamesAsync(allowedScopes));

            _clientRepo.AddApiResources(newScopes);

            // 增加 IAM 需要的 scopes
            if (!allowedScopes.Contains("iam"))
            {
                allowedScopes.Add("iam");
            }

            if (!allowedScopes.Contains("iamApi"))
            {
                allowedScopes.Add("iamApi");
            }

            if (!allowedScopes.Contains(IdentityServerConstants.StandardScopes.OpenId))
            {
                allowedScopes.Add(IdentityServerConstants.StandardScopes.OpenId);
            }

            if (!allowedScopes.Contains(IdentityServerConstants.StandardScopes.Profile))
            {
                allowedScopes.Add(IdentityServerConstants.StandardScopes.Profile);
            }

            if (!allowedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess))
            {
                allowedScopes.Add(IdentityServerConstants.StandardScopes.OfflineAccess);
            }

            string clientId = Guid.NewGuid().ToString();
            string secret   = Helper.GetRandomString(30);

            string[] redirectUris           = null;
            string[] postLogoutRedirectUris = null;
            if (String.IsNullOrWhiteSpace(model.RedirectUris))
            {
                // signin-oidc 与 静默更新都是要作为回调的一部分
                redirectUris = new[] { $"{model.ClientUri.TrimEnd('/')}/signin-oidc", $"{model.ClientUri.TrimEnd('/')}/silent-renew" };
            }
            else
            {
                redirectUris = model.RedirectUris.Split(",", StringSplitOptions.RemoveEmptyEntries);
            }

            if (String.IsNullOrWhiteSpace(model.PostLogoutRedirectUris))
            {
                postLogoutRedirectUris = new[] { $"{model.ClientUri.TrimEnd('/')}/signout-callback-oidc" };
            }
            else
            {
                postLogoutRedirectUris = model.PostLogoutRedirectUris.Split(",", StringSplitOptions.RemoveEmptyEntries);
            }

            IdentityServer4.Models.Client client = new IdentityServer4.Models.Client
            {
                ClientId                         = clientId,
                ClientSecrets                    = { new Secret(secret.Sha256()) },
                AlwaysSendClientClaims           = model.AlwaysSendClientClaims,
                AlwaysIncludeUserClaimsInIdToken = model.AlwaysIncludeUserClaimsInIdToken,
                AccessTokenLifetime              = model.AccessTokenLifetime,
                AllowedScopes                    = allowedScopes,
                AllowedCorsOrigins               = allowedCorsOrigins,
                AllowedGrantTypes                = GrantTypes.CodeAndClientCredentials,
                AllowOfflineAccess               = true, // 允许使用 refresh token 来刷新(因为 Cookie 一般时间会大于 token 的有效期)
                ClientUri                        = model.ClientUri,
                ClientName                       = model.ClientName,
                Description                      = model.Description,
                Enabled = true,
                IdentityTokenLifetime = model.IdentityTokenLifetime,
                LogoUri                = model.LogoUri,
                RedirectUris           = redirectUris,
                PostLogoutRedirectUris = postLogoutRedirectUris,
                RequireConsent         = false,
                RequireClientSecret    = false,
                ClientClaimsPrefix     = Constants.CLIENT_CLAIM_PREFIX,

                // 对于 Code 模式采用 Pkce 扩展
                RequirePkce = true,

                Claims = new ClientClaim[]
                {
                    // 每个 Client 都允许进行同步 perm 的操作
                    new ClientClaim(BuiltInPermissions.PERM_SYNC, BuiltInPermissions.PERM_SYNC)
                }
            };

            _clientRepo.Add(client);

            //await _clientDbContext.SaveChangesAsync();
            return(clientId, secret);
        }