我正在尝试使用webpack使用http Post验证用户登录。我能够传递用户信息并再次验证用户db表。服务器代码工作正常。但是,我偶然发现将响应(一个对象)从服务器传递回客户端。类似的代码在DotNet Core中使用Angular2 SPA(从chsakell Cross-platform SPA中提取和修改代码,使用ASP.NET核心1.0,Angular 2和TypeScript)。但它在webpack中使用Angular2的DotNet Core失败了。我希望有人可以帮助确定问题所在。
System.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using UCHICUDRS.Formatters;
using System.Security.Claims;
using UCHICUDRS.Models;
using UCHICUDRS.Infrastructure.Repositories;
using UCHICUDRS.Infrastructure.Services;
using Newtonsoft.Json.Serialization;
using UCHICUDRS.Infrastructure.Mappings;
namespace UCHICUDRS
{
public class Startup
{
private static string _applicationPath = string.Empty;
private static string _contentRootPath = string.Empty;
public Startup(IHostingEnvironment env)
{
_applicationPath = env.WebRootPath;
_contentRootPath = env.ContentRootPath;
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.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.AddDbContext<UCHICUDRSContext>(options =>
options.UseSqlServer(Configuration["Data:UCHICUDRSConnection:ConnectionString"]));
// Repositories services.AddScoped<ILogRepository, LogRepository>();
services.AddScoped<IRoleRepository, RoleRepository>(); services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IUserRequestRepository, UserRequestRepository>();
services.AddScoped<IUserGroupRepository, UserGroupRepository>();
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
// Services
services.AddScoped<IMembershipService, MembershipService>();
services.AddScoped<IEncryptionService, EncryptionService>();
services.AddAuthentication();
// Polices
services.AddAuthorization(options =>
{
// inline policies
options.AddPolicy("Administrator", policy =>
{
policy.RequireClaim(ClaimTypes.Role, "Administrator");
});
options.AddPolicy("Manager", policy =>
{
policy.RequireClaim(ClaimTypes.Role, "Manager");
});
options.AddPolicy("User", policy =>
{
policy.RequireClaim(ClaimTypes.Role, "User");
});
options.AddPolicy("No Access", policy =>
{
policy.RequireClaim(ClaimTypes.Role, " No Access");
});
});
/*
// Add MVC services to the services container
// Causing http header error
services.AddMvc()
.AddJsonOptions(opt =>
{
var resolver = opt.SerializerSettings.ContractResolver;
if (resolver != null)
{
var res = resolver as DefaultContractResolver;
res.NamingStrategy = null;
}
});
*/
// Add framework services.
services.AddMvc();
services.AddMvc(options =>
{
// The custom formatters need to be added to the MVC middleware, so that it knows how to handle media types 'text/csv'.
options.InputFormatters.Add(new CsvInputFormatter());
options.OutputFormatters.Add(new CsvOutputFormatter());
options.FormatterMappings.SetMediaTypeMappingForFormat("csv", MediaTypeHeaderValue.Parse("text/csv"));
});
}
// 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.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
HotModuleReplacement = true
});
}
else
{
app.UseExceptionHandler("/Home/Error");
}
AutoMapperConfiguration.Configure();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
}
}
operationResult.ts
export class OperationResult {
Succeeded: boolean;
Message: string;
RetData: any;
constructor(succeeded: boolean, message: string, retData: any) {
this.Succeeded = succeeded;
this.Message = message;
this.RetData = retData;
}
}
login.component.ts
import { Component, OnInit } from '@angular/core';
import { ViewChild } from '@angular/core'; // for showModelMsg
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
// import {FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES} from '@angular/forms';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import { Login } from '../../../core/models/login';
import { User } from '../../../core/models/user';
import { Role } from '../../../core/models/role';
import { OperationResult } from '../../../core/models/operationResult';
import { MembershipService } from '../../../core/services/membership.service';
@Component({
selector: 'login',
providers: [MembershipService, NotificationService],
template: require('./login.component.html'),
styles: [require('./account.component.css')]
})
export class LoginComponent implements OnInit {
private _user: Login = new Login('', '', false);
private notificationService: NotificationService; // alertify is no longer be supported so when it put inside the constructor, the html won't display
// private router: Router;
private route: ActivatedRoute;
constructor(private membershipService: MembershipService, private router: Router) { }
ngOnInit() {
this._user.Username = '';
this._user.Password = '';
this._user.RememberMe = false;
}
login(): void {
var _authenticationResult: OperationResult = new OperationResult(false, '', null);
var _creds: User;
this.membershipService.login(this._user)
.subscribe(res => {
_authenticationResult.Succeeded = res.Succeeded;
_authenticationResult.Message = res.Message;
_authenticationResult.RetData = res.RetData;
_creds = _authenticationResult.RetData;
},
error => console.error('Error: ' + error), // error from http call
() => {
if (_authenticationResult.Succeeded) {
this.notificationService.printSuccessMessage('Welcome back ' + this._user.Username + '!');
localStorage.setItem('user', JSON.stringify(_creds));
this.router.navigate(['home']);
}
else {
this.showModelMsg("Login Failed", _authenticationResult.Message);
}
});
};
}
membership.service.ts
import { Http, Response, Request } from '@angular/http';
import { Injectable } from '@angular/core';
import { DataService } from './data.service';
import { Login } from '../models/login';
import { Registration } from '../models/registration';
import { Role } from '../models/role';
import { User } from '../models/user';
import { Observable } from "rxjs/Observable";
@Injectable()
export class MembershipService {
private _accountLoginAPI: string = 'api/account/authenticate/';
private _res: Observable<any>;
public redirectUrl: string; // store the URL so we can redirect after loggin in
constructor(public accountService: DataService) { }
login(creds: Login) {
this.accountService.set(this._accountLoginAPI);
return this.accountService.post(JSON.stringify(creds));
}
}
data.service.ts
import { Http, Response } from '@angular/http';
import { Headers, RequestOptions } from '@angular/http';
import { Injectable } from '@angular/core';
// import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import { Observable } from 'rxjs/Rx';
import { OperationResult } from '../models/operationResult';
@Injectable()
export class DataService {
public _pageSize: number;
public _baseUri: string;
public _headers: Headers;
public _options: RequestOptions;
constructor(public http: Http) {
this.init();
}
init() {
this._headers = new Headers({ 'content-type': 'application/json' });
this._options = new RequestOptions({ headers: this._headers });
}
post(data?: any, mapJson: boolean = true) {
var _authenticationResult: OperationResult = new OperationResult(false, '', null);
if (mapJson) {
var res = this.http.post(this._baseUri, data, this._options)
.map(response => <any>(<Response>response).json());
return res;
}
else
return this.http.post(this._baseUri, data, this._options)
.map(response => response.json())
.catch(this.handleError);
}
}
AccountController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using UCHICUDRS.Models;
using UCHICUDRS.ViewModels;
using UCHICUDRS.Infrastructure.Repositories;
using UCHICUDRS.Infrastructure.Services;
using UCHICUDRS.Infrastructure.Core;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.Cookies;
using AutoMapper;
namespace UCHICUDRS.Controllers
{ // https://chsakell.com/2016/01/01/cross-platform-single-page-applications-with-asp-net-5-angular-2-typescript/
[Route("api/[controller]")]
public class AccountController : Controller
{
private readonly IMembershipService _membershipService;
private readonly IUserRepository _userRepository;
private readonly IRoleRepository _roleRepository;
private readonly ILogRepository _loggingRepository;
public AccountController(IMembershipService membershipService,
IUserRepository userRepository,
IRoleRepository roleRepository,
ILogRepository _errorRepository)
{
_membershipService = membershipService;
_userRepository = userRepository;
_roleRepository = roleRepository;
_loggingRepository = _errorRepository;
}
[HttpPost("authenticate")]
public async Task<IActionResult> Login([FromBody] Login user)
{
IActionResult _result = new ObjectResult(false);
GenericResult _authenticationResult = null;
Console.WriteLine("123");
try
{
MembershipContext _userContext = _membershipService.ValidateUser(user.Username, user.Password);
if (_userContext.User != null)
{
IEnumerable<Role> _roles = _userRepository.GetRoles(user.Username);
List<Claim> _claims = new List<Claim>();
foreach (Role role in _roles)
{
Claim _claim = new Claim(ClaimTypes.Role, role.Name, ClaimValueTypes.String, user.Username);
_claims.Add(_claim);
}
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(new ClaimsIdentity(_claims, CookieAuthenticationDefaults.AuthenticationScheme)),
new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties { IsPersistent = user.RememberMe });
_authenticationResult = new GenericResult()
{
Succeeded = true,
Message = "Authentication succeeded",
RetData = _userContext.User
};
}
else
{
_authenticationResult = new GenericResult()
{
Succeeded = false,
Message = "Username and Password don't match. Authentication failed.",
RetData = null
};
}
}
catch (Exception ex)
{
_authenticationResult = new GenericResult()
{
Succeeded = false,
Message = ex.Message,
RetData = null
};
_loggingRepository.Add(new Log() { Message = ex.Message, StackTrace = ex.StackTrace, RecIn = DateTime.Now });
_loggingRepository.Commit();
}
_result = new ObjectResult(_authenticationResult);
return _result;
}
}
GenericResult.cs
namespace UCHICUDRS.Infrastructure.Core
{
public class GenericResult
{
public bool Succeeded { get; set; }
public string Message { get; set; }
public object RetData { get; set; }
}
}
答案 0 :(得分:0)
取消注释system.cs中的以下代码
system.cs
services.AddMvc()
.AddJsonOptions(opt =>
{
var resolver = opt.SerializerSettings.ContractResolver;
if (resolver != null)
{
var res = resolver as DefaultContractResolver;
res.NamingStrategy = null;
}
});
我对它进行了评论,因为它导致http调用失败。然后我手动将http标头添加到http以使其工作。当我取消注释上述代码时,http post响应将数据传输回客户端。即使代码现在有用,但我也不知道原因。