我需要创建一个带有angular6和aspcore的网站。
我用ASP核心创建服务器,并创建此令牌:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhYzQ3NjJjZi0xNDdmLTJmZmYtZTQ1Yy05ZDNjNjJkYTAwMDEiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQ0MzkwLyIsImlhdCI6MTU0NDg2OTU1OSwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIzMDAyIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImtpYUBraWEuY29tIiwiRGlzcGxheU5hbWUiOiLYotix2LQg2KjYsdmH2KfZhtuMIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9zZXJpYWxudW1iZXIiOiI0Njg0NjM0NjQiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoiMzAwMiIsIm5iZiI6MTU0NDg2OTU1OSwiZXhwIjoxNTQ0ODY5Njc5LCJhdWQiOiJBbnkifQ.zhW3aoRKGaoy-wEbO7RnbdQmxCXSy50pSaqO1OoEwe8",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiMDEyNTQxYi0yZDljLTE2N2UtZDM0Ni1hZjNlNWRiYjMzYzgiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQ0MzkwLyIsImlhdCI6MTU0NDg2OTU1OSwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9zZXJpYWxudW1iZXIiOiIwZGMwMTRmNDc1NTQ1Y2MyYjEwNzUzZjU1YTFlOTQxNyIsIm5iZiI6MTU0NDg2OTU1OSwiZXhwIjoxNTQ0ODczMTU5LCJhdWQiOiJBbnkifQ.8vwTvDJcT8MoOfvqVb7gGzSxbll2_u91bArumJDW65k"
}
这是我寻找userInfo的服务:
public UserInfo(username:string):Observable<IUser>{
return this.http.get<IUser>(`${this.baseUrl+'GetUserInfo/'}${username}`,{headers:{
'Content-Type': 'application/json; charset=utf-8',
'Authorization': 'Bearer ' + this.broserStorage.GetLocalStorage('AccessToken')+this.broserStorage.GetLocalStorage('RefreshToken'),
},
})
.pipe(
tap((user: IUser) => this.log(`GetUserInfo user w/ email=${user}`)),
catchError(this.handleError<IUser>('GetUserInfo user'))
);
}
我发送了请求,但显示了此错误:
GetUserInfo用户失败:https://localhost:44390/api/user/GetUserInfo/kia@kia.com的Http错误响应:401未经授权
什么问题?来自服务器还是Angular?
此代码来自服务器:
[HttpGet("GetUserInfo/{username}")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<IActionResult> GetUSerInfo(string username)
{
UserRoleViewModel URVM = new UserRoleViewModel();
var user = await _applicationUserManager.FindByNameAsync(username);
if (user != null)
{
var roles = await _applicationUserManager.GetRolesAsync(user);
var roleName = await _applicationRoleManager.FindRoleByNameList(roles[0]);
URVM.Id = user.Id;
URVM.Email = user.Email;
URVM.BirthDate = user.BirthDate;
URVM.CreatedDateTime = user.CreatedDateTime;
URVM.FirstName = user.FirstName;
URVM.IsActive = user.IsActive;
URVM.PhoneNmuberConfirmed = user.PhoneNumberConfirmed;
URVM.IsEmailPublic = user.IsEmailPublic;
URVM.LastName = user.LastName;
URVM.TwoFactorEnabled = user.TwoFactorEnabled;
URVM.EmailConfirmed = user.EmailConfirmed;
URVM.LockoutEnabled = user.LockoutEnabled;
URVM.LastVisitDateTime = user.LastVisitDateTime;
URVM.Location = user.Location;
URVM.PhotoFileName = user.PhotoFileName;
URVM.RoleLevel = roleName.RoleLevel;
URVM.Description = roleName.Description;
URVM.roleId = roleName.Id;
URVM.desplayName = user.FirstName + " " + user.LastName;
return Ok(URVM);
}
return BadRequest();
}
此启动:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.WithOrigins("http://localhost:4200") //Note: The URL must be specified without a trailing slash (/).
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddIdentity<User, Role>().AddUserStore<ApplicationUserStore>()
.AddUserManager<ApplicationUserManager>()
.AddRoleStore<ApplicationRoleStore>()
.AddRoleManager<ApplicationRoleManager>()
.AddSignInManager<ApplicationSignInManager>()
.AddDefaultTokenProviders();
services
.AddAuthentication(options =>
{
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["BearerTokens:Issuer"], // site that makes the token
ValidateIssuer = false, // TODO: change this to avoid forwarding attacks
ValidAudience = Configuration["BearerTokens:Audience"], // site that consumes the token
ValidateAudience = false, // TODO: change this to avoid forwarding attacks
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["BearerTokens:Key"])),
ValidateIssuerSigningKey = true, // verify signature to avoid tampering
ValidateLifetime = true, // validate the expiration
ClockSkew = TimeSpan.Zero // tolerance for the expiration date
};
cfg.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents));
logger.LogError("Authentication failed.", context.Exception);
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
var tokenValidatorService = context.HttpContext.RequestServices.GetRequiredService<ITokenValidatorService>();
return tokenValidatorService.ValidateAsync(context);
},
OnMessageReceived = context =>
{
return Task.CompletedTask;
},
OnChallenge = context =>
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents));
logger.LogError("OnChallenge error", context.Error, context.ErrorDescription);
return Task.CompletedTask;
}
};
});
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (context, next) =>
{
var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;
if (error != null && error.Error is SecurityTokenExpiredException)
{
context.Response.StatusCode = 401;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
State = 401,
Msg = "token expired"
}));
}
else if (error != null && error.Error != null)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
State = 500,
Msg = error.Error.Message
}));
}
else
{
await next();
}
});
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseCors("CorsPolicy");
app.UseAuthentication();
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
});
}
修改
我添加了此类:
@Injectable()
export class AuthInterceptorService implements HttpInterceptor {
private delayBetweenRetriesMs = 1000;
private numberOfRetries = 3;
private authorizationHeader = "Authorization";
constructor(
private tokenStoreService: TokenstoreService,
private router: Router) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const accessToken = this.tokenStoreService.getRawAuthToken(AuthTokenType.AccessToken);
if (accessToken) {
console.log('in if')
request = request.clone({
headers: request.headers.set(this.authorizationHeader, `Bearer ${accessToken}`)
});
return next.handle(request).pipe(
retryWhen(errors => errors.pipe(
mergeMap((error: HttpErrorResponse, retryAttempt: number) => {
if (retryAttempt === this.numberOfRetries - 1) {
console.log(`HTTP call '${request.method} ${request.url}' failed after ${this.numberOfRetries} retries.`);
return throwError(error); // no retry
}
switch (error.status) {
case 400:
case 404:
return throwError(error); // no retry
}
return of(error); // retry
}),
delay(this.delayBetweenRetriesMs),
take(this.numberOfRetries)
)),
catchError((error: any, caught: Observable<HttpEvent<any>>) => {
console.error({ error, caught });
if (error.status === 401 || error.status === 403) {
const newRequest = this.getNewAuthRequest(request);
if (newRequest) {
console.log("Try new AuthRequest ...");
return next.handle(newRequest);
}
this.router.navigate(["/accessDenied"]);
}
return throwError(error);
})
);
} else {
// login page
return next.handle(request);
}
}
getNewAuthRequest(request: HttpRequest<any>): HttpRequest<any> | null {
const newStoredToken = this.tokenStoreService.getRawAuthToken(AuthTokenType.AccessToken);
const requestAccessTokenHeader = request.headers.get(this.authorizationHeader);
if (!newStoredToken || !requestAccessTokenHeader) {
console.log(" first =>There is no new AccessToken.", { requestAccessTokenHeader: requestAccessTokenHeader, newStoredToken: newStoredToken });
return null;
}
const newAccessTokenHeader = `Bearer ${newStoredToken}`;
if (requestAccessTokenHeader === newAccessTokenHeader) {
console.log(" second =>There is no new AccessToken.", { requestAccessTokenHeader: requestAccessTokenHeader, newAccessTokenHeader: newAccessTokenHeader });
return null;
}
console.log("third")
return request.clone({ headers: request.headers.set(this.authorizationHeader, newAccessTokenHeader) });
}
}
并将其添加到appmodule中:
{ provide: HTTP_INTERCEPTORS,useClass: AuthInterceptorService,multi: true},
和此请求:
public UserInfo(username:string):Observable<IUser>{
return this.http.get<IUser>(`${this.baseUrl+'GetUserInfo/'}${username}`,{headers:{
'Content-Type': 'application/json; charset=utf-8'
},
})
.pipe(
tap((user: IUser) => this.log(`GetUserInfo user w/ email=${user}`)),
catchError(this.handleError<IUser>('GetUserInfo user'))
);
}
但是它告诉我这个错误:
second =>没有新的AccessToken。 对象{requestAccessTokenHeader: “承载\” \\ “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0NDZlODZiYi01ZTg2LTEyMjQtNTBmYi1jZGNjOWUwMjkzMDEiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQ0MzkwLyIsImlhdCI6MTU0NDg5MzE4NCwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIzMDAyIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImtpYUBraWEuY29tIiwiRGlzcGxheU5hbWUiOiLYotix2LQg2KjYsdmH2KfZhtuMIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9zZXJpYWxudW1iZXIiOiI0Njg0NjM0NjQiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoiMzAwMiIsIm5iZiI6MTU0NDg5MzE4NCwiZXhwIjoxNTQ0ODkzMzA0LCJhdWQiOiJBbnkifQ.NNKPkwayicwLo8K-K1weP7vGAkL8Cpo9Zx-xtrh6I4E \\” \ “”,newAccessTokenHeader: “承载\” \\“eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0NDZlODZiYi01ZTg2LTEyMjQtNTBmYi1jZGNjOWUwMjkzMDEiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQ0MzkwLyIsImlhdCI6MTU0NDg5MzE4NCwiaHR0cDovL3Nja GVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIzMDAyIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImtpYUBraWEuY29tIiwiRGlzcGxheU5hbWUiOiLYotix2LQg2KjYsdmH2KfZhtuMIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9zZXJpYWxudW1iZXIiOiI0Njg0NjM0NjQiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoiMzAwMiIsIm5iZiI6MTU0NDg5MzE4NCwiZXhwIjoxNTQ0ODkzMzA0LCJhdWQiOiJBbnkifQ.NNKPkwayicwLo8K-K1weP7vGAkL8Cpo9Zx-xtrh6I4E \\ “\””} auth-interceptor.service.ts:74:6 对象{标头:{…},状态:401,statusText:“未经授权”,url:“ https://localhost:44390/api/user/GetUserInfo/kia@kia.com”,确定:false,名称:“ HttpErrorResponse”,消息:“ https://localhost:44390/api/user/GetUserInfo/kia@kia.com的Http失败响应:401未经授权”,错误:null} user.service.ts:113:6 GetUserInfo用户失败:https://localhost:44390/api/user/GetUserInfo/kia@kia.com的Http错误响应:401未经授权