问题描述
我一直致力于将我的 Angular 和 .Net Core 应用程序发布到 OpenShift Container Platform。我已将 JWT 授权令牌配置为对用户进行身份验证并获取 User.Identity.Name 信息。
我使用 Angular 作为前端,使用 .Net Core 3.1 作为后端。在本地一切正常,但是当我尝试将我的应用程序发布到 OpenShift 时,它给了我错误的受众和发行者信息。它也没有给我任何令牌范围。
我对它进行了故障排除,发现我从部署到 OpenShift 的应用程序获得的令牌是 v2.0,而它在本地为我提供了 v1.0 令牌。
任何帮助将不胜感激。
这是我的 app.componenet.ts 文件。
import { Component,OnInit,OnDestroy } from '@angular/core';
import { BroadcastService,MsalService } from '@azure/msal-angular';
import { Subscription } from 'rxjs/Subscription';
@Component
({
selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit,OnDestroy
{
loggedIn: boolean;
private subscription: Subscription;
public isIframe: boolean;
token: string;
// --------------------------------------------------------------------
constructor(private broadcastService: BroadcastService,private authService: MsalService) {
}
// --------------------------------------------------------------------
ngOnInit()
{
this.broadcastService.subscribe("msal:loginSuccess",(payload) => {
localStorage.setItem('token',JSON.stringify(payload));
this.token = JSON.parse(localStorage.getItem('token'))['_token'];
this.loggedIn = true;
this.checkoutAccount();
});
}
// --------------------------------------------------------------------
checkoutAccount() {
this.loggedIn = !!this.authService.getAccount();
if (this.m_router.url == "/")
{
if (!this.m_dbService.isAuthorizedUser())
{
this.setUserAndRoles();
}
}
}
// --------------------------------------------------------------------
login() {
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
if (isIE) {
this.authService.loginRedirect();
} else {
this.authService.loginPopup();
}
}
// --------------------------------------------------------------------
logout() {
this.authService.logout();
}
// --------------------------------------------------------------------
ngOnDestroy() {
this.broadcastService.getMSALSubject().next(1);
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
这是我的 app.module.ts 文件。
// Modules
import { NgModule,ErrorHandler,forwardRef } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // new
import { HttpModule } from '@angular/http';
import { HttpClientModule,HTTP_INTERCEPTORS } from '@angular/common/http';
// Routing
import { HashLocationStrategy,LocationStrategy,Location } from '@angular/common';
// Components
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Authentication
import { MsalModule,MsalInterceptor,MsalAngularConfiguration,MSAL_CONFIG,MSAL_CONFIG_ANGULAR,MsalService } from '@azure/msal-angular';
import { Logger,Configuration } from 'msal';
import { environment } from '../environments/environment';
export function loggerCallback(logLevel,message,piiEnabled) {
console.log('client logging' + message);
}
export const protectedResourceMap: Map<string,string[]> = new Map([
[environment.apiUrl,['api://azure-app-client-id/api_consume']]
]);
const isIE = window.navigator.userAgent.indexOf('MSIE ') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1;
@NgModule
({
imports:
[
BrowserModule,BrowserAnimationsModule,ToastrModule.forRoot(),AppRoutingModule,SharedModule,CoreModule.forRoot(),FwModule,HttpModule,HttpClientModule,MsalModule.forRoot({
auth: {
clientId: environment.clientId,authority: environment.authority,redirectUri: environment.redirectUrl
},framework: {
protectedResourceMap: protectedResourceMap
}
},{
consentScopes: ['openid','profile','api://azure-app-client-id/api_consume'],}
)
],declarations:
[
AppComponent
],exports:
[
],providers:
[
Globals,CookieService,AcErrorService,{provide: ErrorHandler,useClass: GlobalErrorHandlerService},Location,{provide: LocationStrategy,useClass: HashLocationStrategy},{
provide: HTTP_INTERCEPTORS,useClass: MsalInterceptor,multi: true
}
],bootstrap: [AppComponent]
})
export class AppModule { }
这是我的 environment.ts 文件。
export const environment = {
production: false,clientId: 'my-app-registration-client-id',authority: 'https://login.microsoftonline.com/my-app-registration-tenant-id',redirectUrl: 'http://localhost:4200/',apiUrl: 'http://localhost:5000/'
};
这是我的 environment.prod.ts 文件。
export const environment = {
production: true,redirectUrl: 'my-openshift-app-url',apiUrl: 'my-openshift-app-url'
};
这是我的 database.service.ts 文件。
export class DatabaseService
{
constructor
(
public m_httpClient: HttpClient
)
{}
public get(NetCoreApiPath): Observable<any>
{
var strUrl;
try
{
strUrl = this.m_globals.getBaseUrl() + p_strApiPath;
return this.m_httpClient.get<any>(strUrl,{ withCredentials: true })
.pipe(map(data => data),catchError(this.handleError));
}
catch(err)
{
console.error(err);
this.sendErrorEmail(err.message,"1");
}
}
}
这是我的 .Net Core appsettings.json 文件。
{
"ConnectionStrings": {
"DefaultConnection": "Server=my-db-server,1433;Initial Catalog=my-db;Integrated Security=true;"
},"Logging": {
"LogLevel": {
"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"
}
},"AllowedHosts": "*","AzureAd": {
"Instance": "https://login.microsoftonline.com/","Domain": "https://MyOrg.onmicrosoft.com/","TenantId": "my-app-registration-tenant-id","Authority": "https://sts.windows.net/my-app-registration-tenant-id/","Audience": "api://my-app-registration-client-id","ClientId": "my-app-registration-client-id",}
}
这是我的 .Net Core startup.cs 文件。
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using API.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
namespace API
{
public class Startup
{
private readonly IWebHostEnvironment _environment;
public Startup(IConfiguration configuration,IWebHostEnvironment env)
{
Configuration = configuration;
_environment = env;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
Configuration.Bind("AzureAd",options);
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,ValidateAudience = true
};
});
services.AddCors(options =>
{
options.AddPolicy("AllowCors",builder => builder
.WithOrigins("http://localhost:4200","my-openshift-app-url")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services
.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
options.MaxIAsyncEnumerableBufferLimit = int.MaxValue;
})
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore
);
var connectionString = Configuration["ConnectionStrings:DefaultConnection"];
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Production")
services.AddDbContext<AppDB>(options =>
options.UseSqlServer(connectionString));
else
services.AddDbContext<AppDB>(options =>
options.UseSqlServer(connectionString));
}
// 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.UseDefaultFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("AllowCors");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
这是我的控制器类。
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Web.Http;
using Microsoft.AspNetCore.Http.Extensions;
using System.Net;
using Microsoft.AspNetCore.Authorization;
using API.Helpers;
namespace API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EmployeeStatusController : ControllerBase
{
private string m_strUserName;
private readonly AppDB db;
public EmployeeStatusController(AppDB context)
{
db = context;
}
[Authorize]
[HttpGet]
public IQueryable<EmployeeStatus> GetEmployeeStatus()
{
try
{
this.m_strUserName = UserHelper.getUserNameOrAlias(User);
IQueryable<EmployeeStatus> data =
from tbl in db.EmployeeStatus
select tbl;
// ----- /get -----
return data;
}
catch (Exception ex)
{
if (m_strError.Length == 0)
{
if (this.showException())
{
m_strError = ex.ToString();
}
}
sendEmail(this.m_strError + ": " + ex.ToString());
throw new System.Web.Http.HttpResponseException(HttpStatusCode.Forbidden);
}
}
}
}
这是我的 UserHelper.cs 类。
namespace API.Helpers
{
public static class UserHelper
{
public static string getUserName(IPrincipal user)
{
return user.Identity.IsAuthenticated ? user.Identity.Name.ToLower() : "";
}
}
}
这是我在本地得到的令牌结果。
{
"aud": "api://client-id","iss": "https://sts.windows.net/tenant-id/","iat":,"nbf":,"exp":,"acr": "1","aio": "","amr": [
""
],"appid": "client-id","appidacr": "0","family_name": "","given_name": "","in_corp": "true","ipaddr": "","name": "","oid": "","onprem_sid": "","rh": "","scp": "api_consume","sub": "","tid": "tenant-id","unique_name": "","upn": "","uti": "","ver": "1.0"
}
这是我将应用发布到 OpenShift 后获得的令牌。
{
"aud": "client-id","iss": "https://login.microsoftonline.com/tenant-id/v2.0","acct": 0,"auth_time":
"ctry": "","email": "","nonce": "","preferred_username": "","sid": "","tenant_ctry": "","tenant_region_scope": "","ver": "2.0","verified_primary_email": [
""
],"verified_secondary_email": [
"",""
],"xms_tpl": "en"
}
您可以看到我获得的两个令牌具有不同的受众、发行者和版本。可能是我缺少一些小配置,但在此阶段的任何帮助将不胜感激。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)