2017-10-13 225 views
1

我有一个MVC应用程序,我正在添加API控制器。核心2身份 - 获取ASPNetUsers.Id

我有通过Cookie和承载令牌(JWT)的身份验证和授权。对于MVC控制器,它使用cookie。为API控制器提供一个令牌。

我想链接数据在一起,这是基于UserID的所有键。

的MVC应用程序的执行

var userid = _userManager.GetUserId(User); 

返回ASPNetUsers.Id值。因此,在使用应用程序时,所有数据都会以GUID作为OwnerID写出。

现在在我的API控制器上,我有完全相同的代码行。

var userid = _userManager.GetUserId(User); 

但是,这是返回用户名而不是用户ID。

我需要它返回相同的值,在ASPNetUsers.Id GUID。

任何想法?你可以在下面看到我一直在尝试的一些事情。

控制器

using Microsoft.AspNetCore.Authentication.JwtBearer; 
using Microsoft.AspNetCore.Authorization; 
using Microsoft.AspNetCore.Identity; 
using Microsoft.AspNetCore.Mvc; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using TechsportiseOnline.Data; 
using TechsportiseOnline.Helpers; 
using TechsportiseOnline.Models; 

namespace TechsportiseOnline.Controllers 
{ 

    /// <summary> 
    /// This class is used as an API for Races 
    /// </summary> 
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 
    [Route("api/[controller]")] 
    public class RaceController : Controller 
    { 
     private readonly ApplicationDbContext _context; 
     private readonly UserManager<ApplicationUser> _userManager; 
     private readonly IAuthorizationService _authorizationService; 
     private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(User); 

     public RaceController(ApplicationDbContext context, IAuthorizationService authorizationService, 
      UserManager<ApplicationUser> userManager) 
     { 
      _context = context; 
      _userManager = userManager; 
      _authorizationService = authorizationService; 


     } 
    /// <summary> 
    /// Get all Races 
    /// </summary> 
    /// <remarks> 
    /// Gets all Races which have been created by the user 
    /// </remarks> 
    /// <returns>All created Races</returns> 

    [HttpGet] 
    public IEnumerable<Race> GetAll() 
    { 
     var test = User.Identity.IsAuthenticated; 
     var userid = _userManager.GetUserId(User); 
     var user = GetCurrentUserAsync(); 

     //Get only records where the OwnerId is not the logged in User. 

     //return _context.Races.Where(p => p.OwnerID == User.GetUserId()).ToList(); 
     return _context.Races.ToList(); 
    } 

    /// <summary> 
    /// Get a single Race 
    /// </summary> 
    /// <remarks> 
    /// Gets the details from a single Race from it's ID 
    /// </remarks> 
    /// <param name="id">Race ID</param> 
    /// <returns>Single Race</returns> 
    [HttpGet("{id}", Name = "GetRace")] 
    public IActionResult GetById(long id) 
    { 
     //Only return the data when it is owned by the same Id 
     //var item = _context.Races.Where(p => p.OwnerID == User.GetUserId()).FirstOrDefault(t => t.ID == id); 
     var item = _context.Races.FirstOrDefault(t => t.ID == id); 

     if (item == null) 
     { 
      return NotFound(); 
     } 

     return new ObjectResult(item); 
    } 

    /// <summary> 
    /// Get all entries for a Race 
    /// </summary> 
    /// <remarks> 
    /// Gets the all the entries from the race ID 
    /// </remarks> 
    /// <param name="id">Race ID</param> 
    /// <returns>All Entries from the given Race ID</returns> 
    [HttpGet("{id}/entries", Name = "GetEntriesByRaceID")] 
    public IEnumerable<RaceEntry> GetAllEntries(long id) 
    { 
     //Only return the data when it is owned by the same Id 
     //Get only records where the OwnerId is not the logged in User. 
     return _context.RaceEntries 
     //return _context.RaceEntries.Where(p => p.OwnerID == User.GetUserId()) 
            .Where(p => p.RaceID == id) 
            .ToList(); 
    } 



    ///// <summary> 
    ///// Get all timings for a Race 
    ///// </summary> 
    ///// <remarks> 
    ///// Gets the all the timings from the race ID 
    ///// </remarks> 
    ///// <param name="id">Race ID</param> 
    ///// <returns>All timings from the given Race ID</returns> 
    //[HttpGet("{id}/timings", Name = "GetTimingsByRaceID")] 
    //public IEnumerable<Timing> GetAllTimings(long id) 
    //{ 

    // //Only return the data when it is owned by the same Id 
    // //Get only records where the OwnerId is not the logged in User. 
    // return _context.Timings.Where(p => p.OwnerId == User.GetUserId()) 
    //        .Where(p => p.RaceId == id) 
    //        .ToList(); 
    //} 

    ///// <summary> 
    ///// Get the results for a Race 
    ///// </summary> 
    ///// <remarks> 
    ///// Gets the all the results from the race ID 
    ///// </remarks> 
    ///// <param name="id">Race ID</param> 
    ///// <returns>All results from the given Race ID</returns> 
    //[HttpGet("{id}/results", Name = "GetResultsByRaceID")] 
    //public IEnumerable<Results> GetAllResults(long id) 
    //{ 
    // List<Results> raceresults = new List<Results>(); 
    // var raceid = id; 

    // foreach (var raceentry in _context.RaceEntries.Where(p => p.OwnerId == User.GetUserId()) 
    //             .Where(p => p.RaceID == id)) 
    // { 
    //  var raceresult = new Results(); 
    //  var racedetails = _context.Races.Where(t => t.OwnerId == User.GetUserId()) 
    //           .FirstOrDefault(t => t.Id == raceid); 
    //  var timingdetails = _context.Timings.Where(t => t.OwnerId == User.GetUserId()) 
    //            .FirstOrDefault(t => t.BibNumber == raceentry.BibNumber); 

    //  var race = _context.Races.Where(t => t.OwnerId == User.GetUserId()) 
    //        .FirstOrDefault(t => t.Id == id); 


    //  raceresult.AthleteUserID = raceentry.AthleteUserId; 
    //  raceresult.Category = "Category"; 
    //  raceresult.CategoryPosition = 1; 
    //  raceresult.ChipTime = DateTime.Now; //timingdetails.EndTime - timingdetails.StartTime; 
    //  raceresult.Club = raceentry.Club; 
    //  raceresult.ClubPosition = 1; 
    //  raceresult.EntryId = raceentry.Id; 
    //  raceresult.FirstName = raceentry.FirstName; 
    //  raceresult.Gender = raceentry.Gender; 
    //  raceresult.GenderPosition = 1; 
    //  raceresult.GunTime = DateTime.Now; //race.RaceStartTime - timingdetails.EndTime; 
    //  raceresult.LastName = raceentry.LastName; 
    //  raceresult.OverallPosition = 0; 
    //  raceresult.RaceDate = race.RaceDate; 
    //  raceresult.RaceID = raceid; 
    //  raceresult.RaceName = race.Name; 
    //  raceresult.ResultId = 1; 
    //  raceresult.Team = raceentry.Team; 
    //  raceresult.TeamPosition = 1; 
    //  raceresults.Add(raceresult); 
    //  //build result object 
    // } 
    // //Only return the data when it is owned by the same Id 
    // //Get only records where the OwnerId is not the logged in User. 
    // return raceresults.ToList(); 
    //} 

    ///// <summary> 
    ///// Publish the results of a Race 
    ///// </summary> 
    ///// <remarks> 
    ///// Publishes the results as Provisional or Final. Final will submit them to RunBritain/PO10 
    ///// </remarks> 
    ///// <returns>The JSON for the created Race</returns> 
    //[HttpPost("{id}/publish", Name = "PublishResults")] 
    //public IActionResult Publish([FromBody] Race item) 
    //{ 
    // if (item == null) 
    // { 
    //  return BadRequest(); 
    // } 

    // _context.Races.Add(item); 

    // //Set Owner ID 
    // item.OwnerId = User.GetUserId(); 

    // _context.SaveChanges(); 

    // return CreatedAtRoute("GetRace", new { id = item.Id }, item); 
    //} 

    /// <summary> 
    /// Creates a Race 
    /// </summary> 
    /// <remarks> 
    /// Creates a Race which can have entrants and timings assigned to it. 
    /// </remarks> 
    [HttpPost] 
    public IActionResult Create([FromBody] RacePost item) 
    { 
     if (item == null) 
     { 
      return BadRequest(); 
     } 

     if (item.Name == null) 
     { 
      return BadRequest("The Race must have a Name"); 
     } 

     var raceitem = new Race 
     { 
      CurrentEntries = item.CurrentEntries, 
      Description = item.Description, 
      MaxEntries = item.MaxEntries, 
      Name = item.Name, 
      ContactName = item.ContactName, 
      ContactEmail = item.ContactEmail, 
      ContactNumber = item.ContactNumber, 
      //OwnerID = User.GetUserId(), 
      RaceDate = item.RaceDate, 
      RaceStartTime = item.RaceStartTime, 
      IsCompleted = item.IsCompleted, 
      IsPublished = item.IsPublished, 
      IsOpenForEntries = item.IsOpenForEntries, 
      LastUpdated = DateTime.Now 
     }; 

     _context.Races.Add(raceitem); 

     _context.SaveChanges(); 

     return CreatedAtRoute("GetRace", new { id = raceitem.ID }, raceitem); 
    } 

    /// <summary> 
    /// Update a Race 
    /// </summary> 
    /// <remarks> 
    /// Update's a Race's details 
    /// </remarks> 
    /// <param name="id">Race ID</param> 
    /// <returns>The JSON for the updated Race</returns> 
    [HttpPut("{id}")] 
    public IActionResult Update(long id, [FromBody] Race item) 
    { 
     if (item == null) 
     { 
      return BadRequest(); 
     } 

     if (item.Name == null) 
     { 
      return BadRequest("The Race must have a Name"); 
     } 

     //var race = _context.Races.Where(t => t.OwnerID == User.GetUserId()) 
     var race = _context.Races 
           .FirstOrDefault(t => t.ID == id); 
     //var race = _context.Races.FirstOrDefault(t => t.ID == id); 
     if (race == null) 
     { 
      return NotFound(); 
     } 

     //race.OwnerID = User.GetUserId(); 
     race.Name = item.Name; 
     race.ContactName = item.ContactName; 
     race.ContactEmail = item.ContactEmail; 
     race.ContactNumber = item.ContactNumber; 
     race.RaceDate = item.RaceDate; 
     race.RaceStartTime = item.RaceStartTime; 
     race.Description = item.Description; 
     race.MaxEntries = item.MaxEntries; 
     race.CurrentEntries = item.CurrentEntries; 
     race.IsCompleted = item.IsCompleted; 
     race.IsPublished = item.IsPublished; 
     race.IsOpenForEntries = item.IsOpenForEntries; 
     race.LastUpdated = DateTime.Now; 


     _context.Races.Update(race); 
     _context.SaveChanges(); 
     return new NoContentResult(); 
    } 


    /// <summary> 
    /// Delete a Race 
    /// </summary> 
    /// <remarks> 
    /// Deletes a Race. Note: This will orphan any related result data and is not recommended! 
    /// </remarks> 
    /// <param name="id">Race ID</param> 
    /// <returns></returns> 
    [HttpDelete("{id}")] 
    public IActionResult Delete(long id) 
    { 
     //var race = _context.Races.Where(p => p.OwnerID == User.GetUserId()).FirstOrDefault(t => t.ID == id); 
     var race = _context.Races.FirstOrDefault(t => t.ID == id); 
     //var race = _context.Races.FirstOrDefault(t => t.Id == id); 

     if (race == null) 
     { 
      return NotFound(); 
     } 

     var raceid = race.ID; 

     ////Delete associated race entries 
     //foreach (var raceentry in _context.RaceEntries.Where(p => p.OwnerId == User.GetUserId()) 
     //            .Where(p => p.RaceID == raceid)) 
     //{ 
     // _context.RaceEntries.Remove(raceentry); 
     //} 

     ////Delete associated race timings 
     //foreach (var timing in _context.Timings.Where(p => p.OwnerId == User.GetUserId()) 
     //            .Where(p => p.RaceId == raceid)) 
     //{ 
     // _context.Timings.Remove(timing); 
     //} 

     //Delete/Save the deletion of the race 
     _context.SaveChanges(); 
     return new NoContentResult(); 
    } 
} 

}

而且Startup.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Identity; 
using Microsoft.EntityFrameworkCore; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 
using TechsportiseOnline.Data; 
using TechsportiseOnline.Models; 
using TechsportiseOnline.Services; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Authorization; 
using Microsoft.AspNetCore.Mvc.Authorization; 
using TechsportiseOnline.Authorization; 
using TechsportiseOnline.Helpers; 
using Swashbuckle.AspNetCore.Swagger; 
using System.IO; 
using Microsoft.Extensions.PlatformAbstractions; 
using static TechsportiseOnline.Helpers.Swagger; 
using Microsoft.AspNetCore.Authentication.JwtBearer; 
using Microsoft.IdentityModel.Tokens; 
using System.Text; 

namespace TechsportiseOnline 
{ 
    public class Startup 
    { 
     public Startup(IConfiguration configuration) 
     { 
      Configuration = configuration; 
     } 

     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.AddDbContext<ApplicationDbContext>(options => 
       options.UseSqlServer(Configuration.GetConnectionString("TechsportiseDB"))); 
                 //options.UseInMemoryDatabase("Teschsportise")); 

      services.AddIdentity<ApplicationUser, IdentityRole>(config => 
       { 
        config.SignIn.RequireConfirmedEmail = true; 
       }) 
       .AddEntityFrameworkStores<ApplicationDbContext>() 
       .AddDefaultTokenProviders(); 

      services.Configure<IdentityOptions>(options => 
      { 
       // Password settings 
       options.Password.RequireDigit = true; 
       options.Password.RequiredLength = 6; 
       options.Password.RequireNonAlphanumeric = false; 
       options.Password.RequireUppercase = false; 
       options.Password.RequireLowercase = false; 
       options.Password.RequiredUniqueChars = 2; 

       // Lockout settings 
       options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); 
       options.Lockout.MaxFailedAccessAttempts = 10; 
       options.Lockout.AllowedForNewUsers = true; 

       // User settings 
       options.User.RequireUniqueEmail = true; 
      }); 

      services.Configure<AuthMessageSenderOptions>(Configuration); 

      //services.ConfigureApplicationCookie(options => 
      //{ 
      // // Cookie settings 
      // options.Cookie.HttpOnly = true; 
      // options.Cookie.Expiration = TimeSpan.FromDays(150); 
      // options.LoginPath = "/Account/Login"; // If the LoginPath is not set here, ASP.NET Core will default to /Account/Login 
      // options.LogoutPath = "/Account/Logout"; // If the LogoutPath is not set here, ASP.NET Core will default to /Account/Logout 
      // options.AccessDeniedPath = "/Account/AccessDenied"; // If the AccessDeniedPath is not set here, ASP.NET Core will default to /Account/AccessDenied 
      // options.SlidingExpiration = true; 
      //}); 

      // Add application services. 
      services.AddTransient<IEmailSender, Email>(); 
      //services.AddTransient<ICreateContact>(); 
      //services.AddTransient<IUpdateContact>(); 

      services.AddSwaggerGen(c => 
      { 
       c.SwaggerDoc("v1", new Info { Title = "Techsportise API", Version = "v1" }); 
       c.OperationFilter<AddRequiredHeaderParameter>(); 
       var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "Techsportise.xml"); 
       c.IncludeXmlComments(filePath); 
      }); 

      services.Configure<JWTSettings>(Configuration.GetSection("JWTSettings")); 


      services.AddAuthentication() 
       .AddCookie() 
       .AddJwtBearer(options => 
       { 
        options.RequireHttpsMetadata = false; 
        options.IncludeErrorDetails = true; 

        var secretKey = Configuration.GetSection("JWTSettings:SecretKey").Value; 
        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey)); 

        options.TokenValidationParameters = new TokenValidationParameters 
        { 

         ValidateIssuer = true, 
         ValidIssuer = Configuration.GetSection("JWTSettings:Issuer").Value, 
         ValidateAudience = true, 
         ValidAudience = Configuration.GetSection("JWTSettings:Audience").Value, 
         ValidateIssuerSigningKey = true, 
         IssuerSigningKey = signingKey, 

        }; 
       }); 



      services.AddMvc(); 

      var skipSSL = Configuration.GetValue<bool>("LocalTest:skipSSL"); 
      // requires using Microsoft.AspNetCore.Mvc; 
      services.Configure<MvcOptions>(options => 
      { 
       // Set LocalTest:skipSSL to true to skip SSL requrement in 
       // debug mode. This is useful when not using Visual Studio. 
       if (!skipSSL) 
       { 
        options.Filters.Add(new RequireHttpsAttribute()); 
       } 
      }); 


      //services.AddMvc(config => 
      //{ 
      // var policy = new AuthorizationPolicyBuilder() 
      //      .RequireAuthenticatedUser() 
      //      .Build(); 
      // config.Filters.Add(new AuthorizeFilter(policy)); 
      //}); 

      services.AddScoped<IAuthorizationHandler, 
         OwnerRaceAuthorizationHandler>(); 

      services.AddSingleton<IAuthorizationHandler, 
            AdminRaceAuthorizationHandler>(); 

      services.AddScoped<IAuthorizationHandler, 
         OwnerRaceEntriesAuthorizationHandler>(); 

      services.AddSingleton<IAuthorizationHandler, 
            AdminRaceEntriesAuthorizationHandler>(); 

     } 

     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 
     public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
     { 
      if (env.IsDevelopment()) 
      { 
       app.UseDeveloperExceptionPage(); 
       app.UseBrowserLink(); 
       app.UseDatabaseErrorPage(); 
      } 
      else 
      { 
       app.UseExceptionHandler("/Home/Error"); 
      } 

      app.UseStaticFiles(); 


      app.UseAuthentication(); 

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

      // Enable middleware to serve generated Swagger as a JSON endpoint. 
      app.UseSwagger(); 

      // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint. 
      app.UseSwaggerUI(c => 
      { 
       c.SwaggerEndpoint("/swagger/v1/swagger.json", "Techsportise API V1"); 
      }); 


     } 
    } 
} 

编辑:这里的TokenController生成令牌

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Authorization; 
using TechsportiseOnline.Models.AccountViewModels; 
using Microsoft.AspNetCore.Identity; 
using TechsportiseOnline.Models; 
using System.Security.Claims; 
using System.IdentityModel.Tokens.Jwt; 
using Microsoft.IdentityModel.Tokens; 
using System.Text; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.Options; 
using TechsportiseOnline.Helpers; 

namespace TechsportiseOnline.Controllers 
{ 
    [Produces("application/json")] 
    [Route("api/Token")] 
    public class TokenController : Controller 
    { 
     private readonly UserManager<ApplicationUser> _userManager; 
     private readonly SignInManager<ApplicationUser> _signInManager; 
     private readonly IConfiguration _configuration; 
     private readonly IOptions<JWTSettings> _jwtConfig; 

     public TokenController(
       UserManager<ApplicationUser> userManager, 
       SignInManager<ApplicationUser> signInManager, 
       IConfiguration configuration, 
       IOptions<JWTSettings> jwtConfig) 
        { 
         _userManager = userManager; 
         _signInManager = signInManager; 
         _configuration = configuration; 
         _jwtConfig = jwtConfig; 


     } 

     [AllowAnonymous] 
     [HttpPost] 
     public async Task<IActionResult> GenerateToken([FromBody] LoginViewModel model) 
     { 
      if (ModelState.IsValid) 
      { 
       var user = await _userManager.FindByEmailAsync(model.Email); 

       if (user != null) 
       { 
        var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false); 
        if (result.Succeeded) 
        { 

         var claims = new[] 
         { 
          new Claim(JwtRegisteredClaimNames.Sub, user.Email), 
          new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), 
         }; 

         var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_jwtConfig.Value.SecretKey.ToString())); 
         var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); 

         var token = new JwtSecurityToken(_jwtConfig.Value.Issuer.ToString(), 
          _jwtConfig.Value.Audience.ToString(), 
          claims, 
          expires: DateTime.Now.AddDays(30), 
          signingCredentials: creds); 

         // return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) }); 

         return new JsonResult(new Dictionary<string, object> 
          { 
          { "access_token", new JwtSecurityTokenHandler().WriteToken(token) }, 
          }); 
        } 
       } 
      } 

      return BadRequest("Could not create token"); 
     } 
    } 
} 
+0

您可以包含示例JWT令牌吗? –

+0

这是我刚刚生成的一个。我也更新了我的帖子,包括该TokenController我使用生成令牌: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkB0ZWNoc3BvcnRpc2UuY28udWsiLCJqdGkiOiJlMzBhNGM2NS02NzZmLTRlZWQtYTA4My1mOWE1YmJhYWMxMTEiLCJleHAiOjE1MTA1ODk1MjUsImlzcyI6InRlY2hzcG9ydGlzZSIsImF1ZCI6IlRlY2hzcG9ydGlzZUFQSSJ9.Q91YbUTlqAa7aW0i6EADl_Lu3J0x7mEgb4YeT5Mk7Hc' –

+0

有一个在您生成的JWT没有用户信息 –

回答

0

感谢Kirk,当他问他的问题时,我能够更快地看到修复程序,而且我查看了令牌生成器控制器。

在我的令牌,我产生了要求

new Claim(JwtRegisteredClaimNames.Sub, user.Email), 

更改,要

new Claim(JwtRegisteredClaimNames.Sub, user.Id), 

解决它。