从客户端调用时,IdentityServer令牌返回未授权

时间:2020-07-28 08:19:33

标签: asp.net-mvc asp.net-core asp.net-identity identityserver4

我正在使用IdentityServer和 我可以从客户端mvc应用程序中的服务器成功获取令牌,但是在启用“授权”时在标头中传递令牌时,出现了未授权错误。 和http客户端使用异步调用。 下面是我的完整代码

不确定从服务器获取令牌时为什么没有得到授权。

请指导/帮助。

谢谢

身份服务器:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            var builder = services.AddIdentityServer(
                options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
            });

            // in-memory, json config
            // builder.AddInMemoryIdentityResources(Configuration.GetSection("IdentityResources"));
            builder.AddInMemoryApiResources(Configuration.GetSection("ApiResources"));
            builder.AddInMemoryClients(Configuration.GetSection("clients"));

            //TODO: replace PROD siging certificate
            builder.AddDeveloperSigningCredential();

            services.AddAuthentication();

            services.AddTransient<ITokenCreationService, TokenService>();

        }

        public void Configure(IApplicationBuilder app)
        {
            if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage();}

            app.UseIdentityServer();
        }
    }

Protected API:

 public void ConfigureServices(IServiceCollection services)
        {
            
            var config = Configuration.GetSection("AuthSettings").Get<AuthSettings>();

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                    .AddJwtBearer(o =>
                    {
                        o.Authority = config.AuthUrl;
                        o.Audience = config.AuthAudience; 
                        o.RequireHttpsMetadata = false;
                        o.SaveToken = true;
                        o.BackchannelHttpHandler = new HttpClientHandler()
                        {
                            ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
                            Proxy = new WebProxy(Configuration["System:Proxy"])
                        };
                    });

            services.AddControllers();
            services.AddSingleton(typeof(IAppLogger<>), typeof(SerilogService<>));
            services.AddCustomMvc();
            KeySettings keySettings = new KeySettings(Configuration.GetSection("KeySettings")["Thumbprint"]);
            services.AddSingleton(keySettings);

            services.AddScoped<CommandQueryMediator>();
            services.AddCommandQueryHandlers(typeof(GetPageMetadata).Assembly);

            var mappingConfig = new MapperConfiguration(mc =>
            {
                mc.AddProfile(new MappingProfile());
                mc.AddProfile(new DomainToDtoMappingProfile());
            });
            IMapper mapper = mappingConfig.CreateMapper();
            services.AddSingleton(mapper);

            // Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Automation API", Version = "v1" });
            });

            IdentityModelEventSource.ShowPII = true;
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseRouting();
            app.UseCors();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
          
        }

客户端MVC应用程序:

public void ConfigureServices(IServiceCollection services)
        {

            var authConfig = Configuration.GetSection("AppSettings").Get<AppSettings>();

            // Adds an instance of the class that contains credentials
            services.AddSingleton(new ClientCredentialsTokenRequest
            {
                Address = authConfig.AuthURL,
                ClientId = authConfig.AuthClientId,
                ClientSecret = authConfig.AuthClientSecret,
                Scope = authConfig.AuthScope
            });

            services.AddControllersWithViews();
            services.AddRepository(Configuration);
            services.AddHttpContextAccessor();
            services.AddDataProtection()
             .SetApplicationName("DataTransition_Web")
             .PersistKeysToFileSystem(new DirectoryInfo(Configuration.GetSection("AppSettings")["DataProtectionKeyPath"]))
             .UseCryptographicAlgorithms(
             new AuthenticatedEncryptorConfiguration()
             {
                 EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
                 ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
             });
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });

            
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())  { app.UseDeveloperExceptionPage();  }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }

            app.UseRouting();
            app.UseAuthentication();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }

使用令牌调用API:

public async Task<ReviewSearchViewModel> SearchReviews()
        {
            try
            {
                var apiClientCredentials = new ClientCredentialsTokenRequest
                {
                    Address = "http://localhost:20102/connect/token",
                    ClientId = "automation.portal",
                    ClientSecret = "0b4168e4-2832-48ea-8fc8-7e4686b3620b",
                    Scope = "automation.apiscope",
                };

                var client = new HttpClient();
                var disco = await client.GetDiscoveryDocumentAsync("http://localhost:20102");
                // 2. Authenticates and get an access token from Identity Server
                var tokenResponse = await client.RequestClientCredentialsTokenAsync(apiClientCredentials);
                var model = new ReviewSearchViewModel();
                ReviewSearchResultDto _reviewSearchResultObj = await WebAPIHelper.GetAPIData<ReviewSearchResultDto>(
                   appSettings.ReviewSearchUrl,
                    loggedinUser.CookieCollection, tokenResponse.AccessToken);
                if (_reviewSearchResultObj != null )
                {
                    model = mapper.Map<ReviewSearchResultDto, ReviewSearchViewModel>(_reviewSearchResultObj, opt =>
                    {
                        opt.AfterMap((src, dest) =>
                        {
                        });
                    });
                    return model;
                }
                else
                {
                    return new ReviewSearchViewModel();
                }
            }
            catch (Exception ex)
            {
                logger.LogWarning("WEB | ERROR | ", ex);
            }

Helper方法GetAPIData:

公共静态字符串GetAPIData(字符串url,字典<字符串,对象>标头数据= null,字符串accessToken = null) {

       string APIsecretkey = "APISecretKeyTest";
       string response = String.Empty;
        HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
        try
        {
            //DEV ONLY
            ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
            //_logger.LogInformation("Starting API Call to " + url);
            //Set HttpWebRequest properties
            httpWebRequest.Method = "GET";
            httpWebRequest.ContentType = "application/json; encoding='utf-8'";
            httpWebRequest.Accept = "application/json; encoding='utf-8'";
            
            //TODO: token type should be from config.
            if(! String.IsNullOrWhiteSpace(accessToken))
                httpWebRequest.Headers.Add("Authorization", "Bearer" + accessToken);
            
            using (HttpWebResponse httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse())
            {
                //_logger.LogInformation("Completed API Call to " + url);
                if (httpWebResponse.StatusCode == HttpStatusCode.OK) //200
                {
                    //Get response stream into StreamReader
                    using (Stream responseStream = httpWebResponse.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(responseStream))
                            response = reader.ReadToEnd();
                    }
                }
                else
                {
                    APIException apiException = new APIException();
                    apiException.StatusCode = httpWebResponse.StatusCode;
                    throw apiException;
                }
            }
        }
        catch (WebException we) when ((we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
        {
            //_logger.LogError("API Notfound Error:",we);
            throw AuthException(we, HttpStatusCode.NotFound);
        }
        catch (WebException we) when ((we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.BadRequest)
        {
            //_logger.LogError("API BadRequest Error:", we);
            throw AuthException(we, HttpStatusCode.BadRequest);
        }
        catch (WebException we) when ((we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.InternalServerError)
        {
            //_logger.LogError("API InternalServerError Error:", we);
            throw AuthException(we, HttpStatusCode.InternalServerError);
        }
        catch (Exception ex)
        { //_logger.LogError("API Exception Error:", ex); 
            throw new Exception(ex.Message);
        }
        finally
        {
            httpWebRequest = null;
        }
        return response;
    }

1 个答案:

答案 0 :(得分:0)

您正在使用`httpWebRequest.Authorization = new AuthenticationHeaderValue(“ Bearer”,accessToken);'

您需要在“载体”和访问令牌字符串之间留一个空格。

最好使用AuthenticationHeaderValue替您处理:

httpWebRequest.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);