IdentityServer3 + Angular4 + WebApi导致401未经授权

时间:2017-08-09 14:25:05

标签: c# angular asp.net-web-api identityserver3

我在WebApi中实现IdentityServer3令牌授权时遇到问题。我的解决方案有一个.NET Core Angular 4客户端项目和一个单独的.NET Framework 4.5.2 WebApi项目。在添加令牌授权之前,WebApi已经过测试并且正在运行。 IdentityServer3登录和身份验证也正常运行。我正在使用angular-auth-oidc-client节点模块。我已经验证了Request Header正在为Content-Type,Accept和Authorization设置指定的属性。以下是一些关键文件的代码。

用户-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import { Subject } from 'rxjs/Rx';
import { OidcSecurityService } from 'angular-auth-oidc-client';

import 'rxjs/add/operator/map';

class User {
    userId: number;
    firstName: string;
    middleName: string;
    lastName: string;
    email: string;
}

@Component({
    selector: 'user-list',
    templateUrl: './user-list.html',
    styleUrls: ['./user-list.css']
})
export class UserListComponent implements OnInit {
    dtOptions: DataTables.Settings = {};
    users: User[] = [];

    dtTrigger: Subject<User> = new Subject();

    constructor(private http: Http, private securityService: OidcSecurityService) { }

    ngOnInit(): void {
        this.dtOptions = {
            searching: true,
            pagingType: 'full_numbers',
            pageLength: 5,
            info: false,
            lengthChange: false
        };

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');
        headers.append('Accept', 'application/json');
        headers.append('Authorization', 'Bearer ' + this.securityService.getToken());

        //this.dtOptions = this.http.get('api/settings/datatables')
        //    .toPromise()
        //    .then(response => response.json());

        this.http.get('/api/home', { headers })
            .map((response: Response) => response.json())
            .subscribe(users => {
                this.users = users;
                this.dtTrigger.next();
            });
    }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app.routes';
import { DataTablesModule } from 'angular-datatables';

import { AppComponent } from './app.component';
import { UserListComponent } from './user-list/user-list.component';
import { PostalCodeComponent } from './postal-code/postal-code.component';

import { AuthModule, OidcSecurityService, OpenIDImplicitFlowConfiguration } from 'angular-auth-oidc-client';

@NgModule({
    declarations: [
        AppComponent,
        UserListComponent,
        PostalCodeComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        HttpModule,
        DataTablesModule,
        AuthModule.forRoot()
    ],
    providers: [OidcSecurityService],
    bootstrap: [AppComponent]
})
export class AppModule {
    constructor(public oidcSecurityService: OidcSecurityService) {
        let settings = new OpenIDImplicitFlowConfiguration();
        settings.stsServer = 'https://identitydev.company.com/oidc/core';
        settings.redirect_url = 'http://localhost:4200';
        settings.client_id = '802523112846585';
        settings.response_type = 'id_token token';
        settings.scope = 'openid app_profile app_client_api';
        settings.post_logout_redirect_uri = 'http://localhost:4200';
        settings.startup_route = '/';
        //settings.forbidden_route = '/Forbidden';
        //settings.unauthorized_route = '/Unauthorized';
        settings.log_console_warning_active = true;
        settings.log_console_debug_active = true;
        //settings.max_id_token_iat_offset_allowed_in_seconds = 10;
        //settings.override_well_known_configuration = true;
        //settings.override_well_known_configuration_url = 'https://localhost:44386/wellknownconfiguration.json';

        // this.oidcSecurityService.setStorage(localStorage);
        this.oidcSecurityService.setupModule(settings);
    }
}

Startup.cs

using Microsoft.Owin;
using Owin;
using System.Web.Http;
using IdentityServer3.AccessTokenValidation;
using System.Net.Http.Headers;
using Microsoft.Owin.Security.OAuth;

[assembly: OwinStartup(typeof(App.API.Test.Startup))]
namespace App.API.Test
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://identitydev.company.com/oidc/core",
                //RequiredScopes = new[] { "app_client_api" },
                ValidationMode = ValidationMode.ValidationEndpoint
            });

            // configure web api
            var config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();
            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
            app.UseWebApi(config);
        }
    }
}

HomeController.cs

using System.Collections.Generic;
using System.Security.Claims;
using System.Web.Http;
using TRAX.Models;

namespace App.API.Test.Controllers
{
    [Authorize]
    [Route("api/home")]
    public class HomeController : ApiController
    {
        [HttpGet]
        public IEnumerable<User> Get()
        {
            UserList list = new UserList();
            return list.GetAll;
        }

        //// GET api/home/{firstname}
        //[HttpGet("{FirstName}")]
        //public List<User> GetByFirstName(string FirstName)
        //{
        //    UserList list = new UserList();
        //    return list.GetUserByFirstName(FirstName);
        //}
    }
}

**注意:有一个模型与该控制器一起返回数据,但您可以相信它返回了正确的列表。

1 个答案:

答案 0 :(得分:1)

显然,解决方案是删除Microsoft在模板项目中创建的Global.ascx文件。然后我更新了Startup.cs文件。

using Microsoft.Owin;
using Owin;
using System.Web.Http;
using IdentityServer3.AccessTokenValidation;

[assembly: OwinStartup(typeof(App.API.Test.Startup))]
namespace App.API.Test
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://identitydev.company.com/oidc/core",
                RequiredScopes = new[] { "app_client_api" },
                ValidationMode = ValidationMode.ValidationEndpoint
            });

            WebApiConfig.Register(config);
            app.UseWebApi(config);
        }
    }
}

我也不需要在客户端API调用中包含Content-Type或Accept标头覆盖。我默认从WebApi返回JSON。