当[授权]放置在控制器

时间:2016-11-30 11:53:08

标签: cors identityserver4

我一直在关注教程here来构建我的应用程序。身份验证方面的一切都很好。现在,我遇到的问题是当我移动到资源服务器以检索数据时。如果我将[Authorize]放在资源服务器中的任何方法上,我会收到错误消息“No'Access-Control-Allow-Origin'标头出现在请求的资源上。因此不允许Origin访问。响应具有HTTP状态代码500.“。如果我删除它一切正常但我无法访问与用户相关的任何声明或角色

我的AuthServer的startup.cs代码摘录如下

public class Startup
{
    string PublicHostUri { get { return "https://localhost:44354"; } }
    private readonly IHostingEnvironment _environment;
    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);
        }
        _environment = env;
        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {

        var connectionString = Configuration["Data:UserAccConnection:ConnectionString"];
        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
        var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "reportbook.auth.pfx"), "");

        var reportbookConnnectionString = Configuration["Data:ReportBookDbConnection:connectionString"];
        services.AddDbContext<ReportBookDbContext>(options =>
            options.UseSqlServer(reportbookConnnectionString));

        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);


        services.AddDbContext<UserDbContext>(options =>
            options.UseSqlServer(connectionString, b => b.MigrationsAssembly(migrationsAssembly)));

        // Register the Identity services.
        services.AddIdentity<ApplicationUser, UserRole>()
            .AddEntityFrameworkStores<UserDbContext, Guid>()
            .AddDefaultTokenProviders();

        services.AddCors();
        services.AddMvc();

        services.AddIdentityServer()
            .AddDefaultEndpoints()

            .AddOperationalStore(builder =>
            builder.UseSqlServer(connectionString,
            options => options.MigrationsAssembly(migrationsAssembly)))

            .AddConfigurationStore(builder =>
            builder.UseSqlServer(connectionString,
            options => options.MigrationsAssembly(migrationsAssembly)))

            .SetSigningCredential(cert)
            .AddAspNetIdentity<ApplicationUser>()
            .AddProfileService<IdentityWithAdditionalClaimsProfileService>();

        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new RequireHttpsAttribute());
        });

        services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();
        services.AddTransient<IUnitOfWorkAsync, UnitOfWork>();
        services.AddScoped<IDataContextAsync, ReportBookDbContext>();



    }

    // 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();
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            InitializeDbTestData(app);
        }else
        {
          app.UseExceptionHandler(
          builder =>
          {
              builder.Run(
                async context =>
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");

                    var error = context.Features.Get<IExceptionHandlerFeature>();
                    if (error != null)
                    {
                        await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
                    }
                });
          });
        }

        app.UseApplicationInsightsRequestTelemetry();

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();
        app.UseCors(builder =>
            builder.AllowAnyOrigin()
            .AllowCredentials()
            .AllowAnyHeader()
            .AllowAnyMethod());

        app.UseCsp(options => options.DefaultSources(directive => directive.Self())
            .ImageSources(directive => directive.Self()
               .CustomSources("*"))
            .ScriptSources(directive => directive.Self()
                .UnsafeInline())
            .StyleSources(directive => directive.Self()
                .UnsafeInline()));

        app.UseXContentTypeOptions();
        app.UseXfo(options => options.Deny());
        app.UseXXssProtection(options => options.EnabledWithBlockMode());

        app.UseIdentity();
        app.UseIdentityServer();

        //app.UseMvc(routes =>
        //{
        //    routes.MapRoute(
        //        name: "default",
        //        template: "{controller=Home}/{action=Index}/{id?}");
        //});

        app.UseMvcWithDefaultRoute();
        app.UseMvc();
        //databaseInitializer.Seed(app).GetAwaiter().GetResult();
    }
    private static void InitializeDbTestData(IApplicationBuilder app)
    {
        using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        {
            scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
            scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>().Database.Migrate();
            scope.ServiceProvider.GetRequiredService<UserDbContext>().Database.Migrate();

            var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();

            if (!context.Clients.Any())
            {
                foreach (var client in Clients.Get())
                {
                    context.Clients.Add(client.ToEntity());
                }
                context.SaveChanges();
            }


            if (!context.Scopes.Any())
            {
                foreach (var clientSope in Scopes.Get())
                {
                    context.Scopes.Add(clientSope.ToEntity());
                }
                context.SaveChanges();
            }
            var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
            var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<UserRole>>();

            if (!userManager.Users.Any())
            {
                foreach (var newUser in Users.Get())
                {
                    ApplicationUser user = new ApplicationUser();
                    user.Id = new Guid();
                    user.EmailConfirmed = true;
                    user.UserName = newUser.Email;
                    user.UserNo = newUser.UserNo;
                    user.FirstName = newUser.FirstName;
                    user.LastName = newUser.LastName;
                    user.Gender = newUser.Gender;
                    user.UserCategory = newUser.UserCategory;
                    user.ZoneInfo = newUser.ZoneInfo;
                    userManager.CreateAsync(user, "Password123!").Wait();
                    userManager.AddClaimAsync(user, new Claim("UserCategory", user.UserCategory)).Wait();
                    foreach (var role in newUser.UserRoles)
                    {
                        if (!roleManager.RoleExistsAsync(role).GetAwaiter().GetResult())
                        {
                            UserRole userRole = new UserRole();
                            userRole.Id = new Guid();
                            userRole.Name = role;
                            roleManager.CreateAsync(userRole).Wait();
                        }
                        userManager.AddToRoleAsync(user, role).Wait();
                        userManager.AddClaimAsync(user, new Claim(JwtClaimTypes.Role, role)).Wait();
                    }
                }
            }
        }
    }
}

资源服务器的startup.cs文件摘录如下

public class Startup
    {
        private IHostingEnvironment _env { get; set; }
        public Startup(IHostingEnvironment env)
        {
            _env = 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; }
        //private static void InitializeDbTestData(IApplicationBuilder app)
        //{
        //    using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        //    {
        //        scope.ServiceProvider.GetRequiredService<ReportBookDbContext>().Database.Migrate();
        //    }
        //}

        // This method gets called by the runtime. Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            var folderForKeyStore = Configuration["Data:keystore:KeyStoreFolderWhichIsBacked"];
            var cert = new X509Certificate2(Path.Combine(_env.ContentRootPath, "reportbook.auth.pfx"), "");

            services.AddDataProtection()
                .SetApplicationName("ReportBook")
                .ProtectKeysWithDpapiNG("CERTIFICATE=Hashid:" + cert.Thumbprint,flags: DpapiNGProtectionDescriptorFlags.None);

            services.AddDbContext<ReportBookDbContext>(options =>
                options.UseSqlServer(Configuration["Data:ReportBookDbConnection:connectionString"],
                b => b.MigrationsAssembly("ReportBook.Resource")));         

            // Add framework services.
            services.AddCors();
            services.AddApplicationInsightsTelemetry(Configuration);
            services.AddTransient<IEmailSender, AuthMessageSender>();
            services.AddTransient<ISmsSender, AuthMessageSender>();



            services.AddMvc();
        }

        // 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.UseDeveloperExceptionPage();

            app.UseStatusCodePagesWithReExecute("/error");

            if (env.IsDevelopment())
            {
                //InitializeDbTestData(app);
            }

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            IdentityServerAuthenticationOptions identityServerValidationOptions = new IdentityServerAuthenticationOptions
            {
                Authority = "https://localhost:44354/",
                ScopeName = "resource_server",
                ScopeSecret = new IdentityServer4.Models.Secret("scopeSecret".Sha256()).ToString(),
                AutomaticAuthenticate = true,
                SupportedTokens = SupportedTokens.Both,
                AutomaticChallenge = true
            };
            app.UseIdentityServerAuthentication(identityServerValidationOptions);

            app.UseApplicationInsightsRequestTelemetry();

            app.UseApplicationInsightsExceptionTelemetry();

            app.UseExceptionHandler(
              builder =>
              {
                  builder.Run(
                    async context =>
                    {
                        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                        context.Response.Headers.Add("Access-Control-Allow-Origin", "*");

                        var error = context.Features.Get<IExceptionHandlerFeature>();
                        if (error != null)
                        {
                           await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
                        }
                    });
              });
            app.UseCors(builder =>
                builder.AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowCredentials());
            app.UseMvc();
        }
    }

以下是控制器的摘录,其中我试图触及的方法

[HttpGet("GetInstitutions")]
        //[Authorize]
        public IActionResult GetInstitutions([FromQuery]InstitutionSearchQry model)
        {
            var authorisation = Request.Headers["Authorization"];
            bool auth = User.Identity.IsAuthenticated;
            IEnumerable<Institution> _institutions = null;
            string userCategory = User.Claims.Where(a => a.Type == "UserCategory").Select(a => a.Value).FirstOrDefault().ToString();
            string zoneInfo = User.Claims.Where(a => a.Type == "ZoneInfo").Select(a => a.Value).FirstOrDefault().ToString();
            string userNo = User.Claims.Where(a => a.Type == "UserNo").Select(a => a.Value).FirstOrDefault().ToString();
            bool admin = User.IsInRole("Admin");

            List<Student> students = new List<Student>();

            //Institution institution = _institutionService.Find(a => a.InstitutionID == zoneInfo);
            var pagination = Request.Headers["Pagination"];

            if (!string.IsNullOrEmpty(pagination))
            {
                string[] vals = pagination.ToString().Split(',');
                int.TryParse(vals[0], out page);
                int.TryParse(vals[1], out pageSize);
            }

            switch (userCategory)
            {
                case "Guardian":
                    {

                        students = _guardianService.GetStudents(userNo).ToList();
                        _institutions = _admissionService.GetInstitutions(students.Select(a => a.StudentID).ToList(),model.StartYear,model.EndYear, s => s.Term.AcademicYear.Institution.UniversityInstitutes.Select(a => a.University));
                    }
                    break;
                case "Student":
                    {
                        _institutions = _admissionService.GetInstitution(userNo,s=>s.Term.AcademicYear.Institution.UniversityInstitutes.Select(a=>a.University));
                    }
                    break;
                default:
                    {
                        _institutions = _institutionService.GetInstitutions(a => a.AdministrativeStructure.ZoneInfo == zoneInfo && a.Level.LevelName==model.Level, page, pageSize, out totalCount, s => s.AdministrativeStructure, s => s.Level,s=>s.UniversityInstitutes.Select(a=>a.University));
                    }
                    break;
            }
            if (!String.IsNullOrEmpty(model.Level) && model.Level != "myschool")
            {
                _institutions = _institutions.Where(a => a.Level.LevelName == model.Level);
            }

            var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);


            Response.AddPagination(page, pageSize, totalCount,totalPages);
            Response.AddIdentityInfo(userCategory, admin, userNo, zoneInfo);
            IEnumerable<InstitutionDataViewModel> _instDataModel = Mapper.Map<IEnumerable<Institution>, IEnumerable<InstitutionDataViewModel>>(_institutions);
            return new OkObjectResult(_instDataModel);
        }

以下是对资源服务器进行调用的角度2代码

@Injectable()
export class InstitutionService {
    private resourceApiUrl: string;
    private headers: Headers;
    private storage: any;
    private actionUrl: string;
    public totalItems: number;


    constructor(private _http: Http,
        private itemsService: ItemsService,
        private _configuration: Configuration,
        private _router: Router,
        private _authService: AuthService) {
        this.resourceApiUrl = `${_configuration.resourceServer}api/Institution/`;   
    }
    private SetHeaders(page?: number, itemsPerPage?: number) {
        this.headers = new Headers();
        this.headers.append('Content-Type', 'application/json');
        this.headers.append('Accept', 'application/json');
        if (page != null && itemsPerPage != null) {
            this.headers.append('Pagination', page + ',' + itemsPerPage);
        }

        var token = this._authService.GetToken();
        if (token !== "") {
            let tokenValue = 'Bearer ' + token;
            console.log("tokenValue:" + tokenValue);
            this.headers.append('Authorization', tokenValue);
        }
    }
    public GetInstitutions = (InstitutionSearchQry?: any, page?: number, itemsPerPage?: number): Observable<PaginatedResult<IInstitution[]>> => {
        this.SetHeaders(page, itemsPerPage);
        var paginatedResult: PaginatedResult<IInstitution[]> = new PaginatedResult<IInstitution[]>();
        let options = new RequestOptions({ headers: this.headers, body: '' });
        if (!InstitutionSearchQry.level) {
            this.actionUrl = "GetInstitutions";
        } else {
            this.actionUrl = "GetInstitutions/", InstitutionSearchQry;

        }

        return this._http.get(this.resourceApiUrl + this.actionUrl, options)
            .map((res: Response) => {
                //console.log(res.headers.keys());
                paginatedResult.result = res.json();
                if (res.headers.get("Pagination") != null) {
                    //var pagination = JSON.parse(res.headers.get("Pagination"));
                    var paginationHeader: Pagination = this.itemsService.getSerialized<Pagination>(JSON.parse(res.headers.get("Pagination")));
                    paginatedResult.pagination = paginationHeader;
                }
                if (res.headers.get("IdentityInfo") != null) {
                    var identityInfo: IdentityInfo = this.itemsService.getSerialized<IdentityInfo>(JSON.parse(res.headers.get("IdentityInfo")));
                    paginatedResult.identityInfo = identityInfo;
                }
                this.totalItems = paginatedResult.pagination.TotalItems;
                return paginatedResult;
            }).catch(this.handleError);
    };


}

因此,AuthServer端提供的授权信息基本上没有到达资源服务器。 可以看出我在两个文件中都添加了“CORS”服务。

1 个答案:

答案 0 :(得分:0)

将此插件用于Chrome浏览器。 get from here