Azure с Identity Server 4 Ошибка: приложение перенаправлено слишком много раз - PullRequest
0 голосов
/ 28 января 2019

Я использую Identity Server 4 с .net Core 2.0.Когда я развернул веб-интерфейс API с помощью служб приложений Azure, он успешно развернулся, но при просмотре он показывает ошибку, как приложение перенаправляется слишком много раз.Это мой код Startup.cs

 using System;
using System.Collections.Generic;
using Autofac;
using Dapper;
using FluentValidation.AspNetCore;
using IdentityServer4.Services;
using IdentityServer4.Validation;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Mvms.Application.Abstract;
using Mvms.Application.Abstract.Services;
using Mvms.Data;
using Mvms.Data.IdentityClasses;
using Mvms.WebApi.Auth;
using Mvms.WebApi.Helpers;
using Mvms.WebApi.Resources;
using NetEscapades.AspNetCore.SecurityHeaders;
using NetEscapades.AspNetCore.SecurityHeaders.Infrastructure;
using Serilog;
using Swashbuckle.AspNetCore.Swagger;

namespace Mvms.WebApi
{
    public class Startup
    {
        private readonly IServiceProvider _provider;
        private readonly IConfiguration _configuration;
        private readonly ILogger<DefaultCorsPolicyService> _logger;
        private readonly IHostingEnvironment _environment;

        public Startup(
            IConfiguration configuration,
            IServiceProvider provider,
            ILogger<DefaultCorsPolicyService> logger,
            IHostingEnvironment environment)
        {
            _provider = provider;
            _logger = logger;
            _environment = environment;
            _configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            var conStr = _configuration.GetConnectionString("DefaultConnection");
            var jwtAuthority = _configuration["JwtAuthority:WebSite"];

            services.AddMultitenancy<TenantBasicInfo, CachingAppTenantResolver>();

            services.AddDbContext<MvmsDataContext>(options => options.UseSqlServer(conStr), ServiceLifetime.Scoped);

            services.AddScoped<ILanguageCache, LanguageCache>(); //one cache per http request
            services.AddScoped<ILanguageIds, LanguageIds>(); //one cache per http request

            SqlMapper.AddTypeHandler(new DateTimeHandler()); //UTC dates for Dapper

            void IdentityOptions(IdentityOptions o)
            {
                //password options
                o.Password.RequireDigit = true;
                o.Password.RequireLowercase = true;
                o.Password.RequireUppercase = true;
                o.Password.RequireNonAlphanumeric = true;
                o.Password.RequiredLength = 8;
                o.Password.RequiredUniqueChars = 1;
            }

            services
                .AddIdentity<ApplicationUser, ApplicationRole>(IdentityOptions)
                .AddEntityFrameworkStores<MvmsDataContext>()
                .AddDefaultTokenProviders();

            services
                 .AddIdentityServer()
                 .AddSigningCertificate(_configuration, _environment)
                 .AddAspNetIdentity<ApplicationUser>()
                 .AddOperationalStore(x => x.ConfigureDbContext = db => db.UseSqlServer(conStr))
                 .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
                 .AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
                 .AddInMemoryClients(IdentityServerConfig.GetClients());

            services.AddTransient<IResourceOwnerPasswordValidator, MultiTenantPasswordValidator>();

            services
                .AddAuthorization(x =>
                {
                    x.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
                        .RequireAuthenticatedUser()
                        .Build();
                })
                .AddAuthentication(o =>
                {
                    o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, jwt =>
                {
                    jwt.TokenValidationParameters = new TokenValidationParameters
                    {
                        IssuerValidator = (issuer, token, parameters) =>
                        {
                            var acc = _provider.GetService<IHttpContextAccessor>();
                            var apiTenant = acc.HttpContext.Request.Host.Value;
                            var authTenant = new Uri(issuer).Host;
                            //if (apiTenant == authTenant)
                            //{
                            //    throw new SecurityTokenInvalidIssuerException();
                            //}
                            return issuer;
                        },
                        AudienceValidator = (audiences, token, parameters) => true
                    };
                    jwt.Audience = $"{jwtAuthority}/resources";
                    jwt.Authority = jwtAuthority;
                    jwt.RequireHttpsMetadata = false;
                });

            services.AddCors();

            var validateAttribute = new ValidateModelAttribute(new LanguageDetector(), new MessageTranslator());

            services
                .AddMvcCore(x => x.Filters.Add(validateAttribute)) //validate models of all actions
                .AddAuthorization()
                .AddJsonFormatters(t => t.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'")
                .AddFluentValidation(x => x.RegisterValidatorsFromAssemblyContaining<Startup>())
                .AddApiExplorer()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Title = "Takamul MVMS", Version = "v1" });
                c.DescribeAllEnumsAsStrings();

                // Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
                c.AddSecurityDefinition("oauth2", new OAuth2Scheme
                {
                    Type = "oauth2",
                    Flow = "password",
                    TokenUrl = "/connect/token",
                    Scopes = new Dictionary<string, string>
                    {
                        { "api", "SPA and Mobile API" }
                    }
                });

                c.SchemaFilter<SwaggerFluentValidationProvider>();
                c.SchemaFilter<SwaggerSampleModelProvider>();
                c.OperationFilter<SwaggerAuthDefinitionProvider>();
                c.OperationFilter<SwaggerLanguageHeaderProvider>();
            });

            var cors = new DefaultCorsPolicyService(_logger)
            {
                AllowedOrigins =
                {
                    "http://localhost:4200", // for public portal local
                    "http://localhost:4201",//for admin portal local
                    "https://mvms-admin.azurewebsites.net", // for admin portal staging
                    "https://mvms-public.azurewebsites.net",//for public portal staging
                    "http://localhost:63342",
                    "https://letsadd.azureedge.net",
                    "https://mvms-release-cdn.azureedge.net",
                    "https://default.release.mvmsx.net/",
                    "https://citizenship.aramco.letsadd.org",
                    "https://ithra.aramco.letsadd.org"
                } //ng serve + identity server
            };
            services.AddSingleton<ICorsPolicyService>(cors);
            services.AddMemoryCache();

            services.AddHttpClient();
        }

        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterAssemblyModules(Assemblies.Get());
        }

        public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            ILoggerFactory loggerFactory,
            ILanguageDetector detector,
            IMessageTranslator translator,
            IConfiguration config)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseStatusCodePages();
            }

            app.UseHsts();

            if (env.IsDevelopment() || env.IsRelease())
            {
                app.UseSwagger();
            }
            else
            {
                //protect swagger
                bool SwaggerIpFilter(HttpContext http)
                {
                    return http.Request.Path.Equals("/swagger/v1/swagger.json")
                           && http.Connection.RemoteIpAddress.ToString()
                               .Equals(_configuration["Swagger:Ip"], StringComparison.Ordinal);
                }

                app.MapWhen(SwaggerIpFilter, builder => builder.UseSwagger());
            }

            var policyCollection = new HeaderPolicyCollection()
                .AddFrameOptionsDeny()
                .AddXssProtectionBlock()
                .AddContentTypeOptionsNoSniff()
                .AddStrictTransportSecurityMaxAgeIncludeSubDomains(7776000) //minimum recommended value
                .AddReferrerPolicyStrictOriginWhenCrossOrigin()
                .RemoveServerHeader()
                .RemoveCustomHeader("X-Powered-By")
                .AddContentSecurityPolicy(builder =>
                {
                    builder.AddObjectSrc().None();
                    builder.AddFormAction().Self();
                    builder.AddFrameAncestors().None();
                });

            app.UseSecurityHeaders(policyCollection);

            app.UseCors(x =>
                x.WithOrigins(
                    "http://localhost:4200", // for public portal local
                    "http://localhost:4201",//for admin portal local
                    "https://mvms-admin.azurewebsites.net", // for admin portal staging
                    "https://mvms-public.azurewebsites.net",//for public portal staging                        "http://localhost:63342",
                    "https://letsadd.azureedge.net",
                    "https://mvms-release-cdn.azureedge.net",
                    "https://default.release.mvmsx.net/",
                    "https://citizenship.aramco.letsadd.org",
                    "https://ithra.aramco.letsadd.org") // ng serve + web api
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()); // tenant sub-domains

            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Takamul MVMS V1");
                c.OAuthClientId("client-spa");
                c.OAuthClientSecret("secret");
                c.OAuthScopeSeparator(" ");
                c.OAuthUseBasicAuthenticationWithAccessCodeGrant();

                c.DocExpansion(env.IsRelease() ? DocExpansion.List : DocExpansion.None);
            });


            app.AddAngularRoutes(env, config);
            app.UseStaticFiles(new StaticFileOptions
            {
                OnPrepareResponse = ctx =>
                {
                    //do NOT cache the index because it contains names of the bundles

                    var cacheHeader = "public, max-age=31536000";
                    if (ctx.File.Name.EndsWith("index.html", StringComparison.OrdinalIgnoreCase) ||
                        ctx.File.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
                    {
                        cacheHeader = "no-cache, no-store, must-revalidate";
                    }

                    ctx.Context.Response.Headers.Append("Cache-Control", cacheHeader);
                }
            });

            app.CorrectStatusCode(loggerFactory, detector, translator); //set the http code 400 when it's needed

            loggerFactory.AddSerilog();

            app.UseMultitenancy<TenantBasicInfo>();

            app.UseIdentityServer();

            app.UseMvcWithDefaultRoute();
        }
    }
}

Он отлично работает в локальной среде.Как я думаю, проблема с конфигурацией https.

...