登录后无法获取数据。
我将 IdentityServer4 与 WebApi 一起使用。只要我不发送任何授权书,一切都会正常进行。我正在使用 Damien Bod 的授权拦截器。
当我发送承载时,我得到了这个:
GET https://localhost:44373/api/pages/10 10:1 XMLHttpRequest 无法加载https://localhost:44373/api/pages/10。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问源“ http://localhost:3000 ”。响应的 HTTP 状态代码为 500。
只要我不将 Authorization 标头添加到 http 请求,这就会起作用。
我正在使用此处找到的 IdentityServer 示例: https ://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/MVC%20and%20API/src
安全服务和授权拦截器都在这里找到: https ://github.com/damienbod/AspNet5IdentityServerAngularImplicitFlow
所以问题是在我登录并尝试从 API 检索数据后,我收到上述错误。
API - Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
//services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
// .AllowAnyMethod()
// .AllowAnyHeader()));
//var policy = new Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy();
//policy.Headers.Add("*");
//policy.Methods.Add("*");
//policy.Origins.Add("*");
//policy.SupportsCredentials = true;
//services.AddCors(x => x.AddPolicy("AllowAll", policy));
services.AddEntityFramework()
.AddEntityFrameworkSqlServer()
.AddDbContext<AsklepiosContext>(options =>
options.UseSqlServer(@"Server = .\SQLEXPRESS; Trusted_Connection = true; Database = AsklepiosTrunk; MultipleActiveResultSets = true;"));
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
var guestPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireClaim("scope", "api1")
.Build();
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizeFilter(guestPolicy));
});
//DI
// some services here ..
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseStaticFiles();
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
//app.UseCors("AllowAll");
//JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
//var jwtBearerOptions = new JwtBearerOptions()
//{
// Authority = "https://localhost:44301",
// Audience = "https://localhost:44301/resources",
// AutomaticAuthenticate = true,
// // required if you want to return a 403 and not a 401 for forbidden responses
// AutomaticChallenge = true
//};
//app.UseJwtBearerAuthentication(jwtBearerOptions);
//JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
//var jwtBearerOptions = new JwtBearerOptions()
//{
// Authority = "https://localhost:44302",
// Audience = "https://localhost:44302/resources",
// AutomaticAuthenticate = true,
// // required if you want to return a 403 and not a 401 for forbidden responses
// AutomaticChallenge = true,
//};
//app.UseJwtBearerAuthentication(jwtBearerOptions);
//JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseCors("AllowAll");
app.UseCors(policy =>
{
policy.WithOrigins(
"http://localhost:3000");
policy.AllowAnyHeader();
policy.AllowAnyMethod();
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "https://localhost:44301",
RequireHttpsMetadata = false,
ScopeName = "api1",
AutomaticAuthenticate = true
});
//app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
//{
// Authority = "https://localhost:44301",
// RequireHttpsMetadata = false,
// ScopeName = "dataEventRecords",
// AutomaticAuthenticate = true
//});
app.UseMvc();
}
}
授权拦截器.ts
import { urls } from "../constants";
class AuthorizationInterceptor {
private static _instance: AuthorizationInterceptor;
private baseUrl: string;
public static Factory($q: angular.IQService, localStorageService, $window) {
AuthorizationInterceptor._instance = new AuthorizationInterceptor($q, localStorageService, $window);
return AuthorizationInterceptor._instance;
}
constructor(private $q: angular.IQService, private localStorageService, private $window) {
console.log("AuthorizationInterceptor created");
}
public request(requestSuccess) {
const self = AuthorizationInterceptor._instance;
requestSuccess.headers = requestSuccess.headers || {};
if (self.localStorageService.get("authorizationData") !== null &&
self.localStorageService.get("authorizationData") !== "") {
// when it adds this header i get CORS Error
requestSuccess.headers.Authorization = "Bearer " + self.localStorageService.get("authorizationData");
}
return requestSuccess || self.$q.when(requestSuccess);
}
public responseError(responseFailure) {
const self = AuthorizationInterceptor._instance;
console.log("console.log(responseFailure);");
console.log(responseFailure);
if (responseFailure.status === 403) {
alert("forbidden");
self.$window.location = "https://localhost:44389/forbidden";
self.$window.href = "forbidden";
} else if (responseFailure.status === 401) {
alert("unauthorized");
self.localStorageService.set("authorizationData", "");
}
return self.$q.reject(responseFailure);
}
}
export default AuthorizationInterceptor;
安全服务.ts
import DataService from "./dataservice";
import { urls } from "../constants";
class SecurityService {
private baseUrl: string;
private isAuthorized: boolean = false;
private hasAdminRole: boolean = false;
constructor(private $http, private $log, private $q, private $rootScope, private $window, private $state,
private localStorageService, private $stateParams) {
this.baseUrl = `${urls.baseApiUrl}`;
console.log("return url: " + this.$stateParams.returnurl);
$log.info("SecurityService called");
// what to put this ?
this.$rootScope.IsAuthorized = false;
this.$rootScope.HasAdminRole = false;
}
public resetAuthorizationData() {
this.localStorageService.set("authorizationData", "");
this.localStorageService.set("authorizationDataIdToken", "");
this.$rootScope.IsAuthorized = false;
this.$rootScope.HasAdminRole = false;
}
public setAuthorizationData(token, id_token) {
if (this.localStorageService.get("authorizationData") !== "") {
this.localStorageService.set("authorizationData", "");
}
this.localStorageService.set("authorizationData", token);
this.localStorageService.set("authorizationDataIdToken", id_token);
this.$rootScope.IsAuthorized = true;
let data: any = this.getDataFromToken(token);
if (data.role !== undefined) {
for (let i = 0; i < data.role.length; i++) {
if (data.role[i] === "dataEventRecords.admin") {
this.$rootScope.HasAdminRole = true;
}
}
}
}
public authorize() {
console.log("AuthorizedController time to log on");
// GET /authorize?
// response_type=code%20id_token
// &client_id=s6BhdRkqt3
// &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
// &scope=openid%20profile%data
// &nonce=n-0S6_WzA2Mj
// &state=af0ifjsldkj HTTP/1.1
const authorizationUrl = "https://localhost:44302/connect/authorize";
const client_id = "angularclient";
const redirect_uri = "http://localhost:3000/authorized";
const response_type = "id_token token";
const scope = "openid profile api1";
const nonce = "N" + Math.random() + "" + Date.now();
const state = Date.now() + "" + Math.random();
this.localStorageService.set("authNonce", nonce);
this.localStorageService.set("authStateControl", state);
console.log("AuthorizedController created. adding myautostate: " + this.localStorageService.get("authStateControl"));
const url =
authorizationUrl + "?" +
"response_type=" + encodeURI(response_type) + "&" +
"client_id=" + encodeURI(client_id) + "&" +
"redirect_uri=" + encodeURI(redirect_uri) + "&" +
"scope=" + encodeURI(scope) + "&" +
"nonce=" + encodeURI(nonce) + "&" +
"state=" + encodeURI(state);
this.$window.location = url;
}
public doAuthorization() {
this.resetAuthorizationData();
if (this.$window.location.hash) {
this.authorizeCallback();
} else {
this.authorize();
}
}
public logoff() {
// var id_token = localStorageService.get("authorizationDataIdToken");
// var authorizationUrl = 'https://localhost:44330/connect/endsession';
// var id_token_hint = id_token;
// var post_logout_redirect_uri = 'https://localhost:44347/unauthorized.html';
// var state = Date.now() + "" + Math.random();
// var url =
// authorizationUrl + "?" +
// "id_token_hint=" + id_token_hint + "&" +
// "post_logout_redirect_uri=" + encodeURI(post_logout_redirect_uri) + "&" +
// "state=" + encodeURI(state);
// ResetAuthorizationData();
// $window.location = url;
// 19.02.2106: temp until connect/endsession is implemented in IdentityServer4 NOT A PROPER SOLUTION!
this.resetAuthorizationData();
this.$window.location = "https://localhost:44389/unauthorized.html";
}
private urlBase64Decode(str) {
let output = str.replace("-", "+").replace("_", "/");
switch (output.length % 4) {
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw "Illegal base64url string!";
}
return window.atob(output);
}
private getDataFromToken(token) {
let data = {};
if (typeof token !== "undefined") {
let encoded = token.split(".")[1];
data = JSON.parse(this.urlBase64Decode(encoded));
}
return data;
}
private authorizeCallback() {
console.log("AuthorizedController created, has hash");
let hash = window.location.hash.substr(1);
let result: any = hash.split("&").reduce(function (result2, item) {
let parts = item.split("=");
result2[parts[0]] = parts[1];
return result2;
}, {});
let token = "";
let id_token = "";
let authResponseIsValid = false;
if (!result.error) {
if (result.state !== this.localStorageService.get("authStateControl")) {
console.log("AuthorizedCallback incorrect state");
} else {
token = result.access_token;
id_token = result.id_token;
let dataIdToken: any = this.getDataFromToken(id_token);
console.log(dataIdToken);
// validate nonce
if (dataIdToken.nonce !== this.localStorageService.get("authNonce")) {
console.log("AuthorizedCallback incorrect nonce");
} else {
this.localStorageService.set("authNonce", "");
this.localStorageService.set("authStateControl", "");
authResponseIsValid = true;
console.log("AuthorizedCallback state and nonce validated, returning access token");
}
}
}
if (authResponseIsValid) {
this.setAuthorizationData(token, id_token);
console.log(this.localStorageService.get("authorizationData"));
this.$state.go("overviewindex");
} else {
this.resetAuthorizationData();
this.$state.go("unauthorized");
}
}
}
SecurityService.$inject = ["$http", "$log", "$q", "$rootScope", "$window", "$state", "localStorageService", "$stateParams"];
export default SecurityService;