我正在使用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;
}
答案 0 :(得分:0)
您正在使用`httpWebRequest.Authorization = new AuthenticationHeaderValue(“ Bearer”,accessToken);'
您需要在“载体”和访问令牌字符串之间留一个空格。
最好使用AuthenticationHeaderValue
替您处理:
httpWebRequest.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);