提交 1e6d8f69 编写于 作者: 麦壳饼's avatar 麦壳饼

fix for jwt

上级 e031e87f
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IoTSharp.Hub
{
public class AppSettings
{
public string DataBase { get; set; }
public string JwtKey { get; set; }
public string JwtExpireDays { get; set; }
public string JwtIssuer { get; set; }
}
}
using IoTSharp.Hub.Data;
using IoTSharp.Hub.Dtos;
using IoTSharp.Hub.Extensions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
......@@ -48,7 +49,6 @@ namespace IoTSharp.Hub.Controllers
{
try
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, false);
if (result.Succeeded)
{
......@@ -56,7 +56,7 @@ namespace IoTSharp.Hub.Controllers
var token = await _userManager.GenerateJwtTokenAsync(appUser);
return Ok(new LoginResult()
{
Succeeded= result.Succeeded,
Succeeded = result.Succeeded,
Token = token,
UserName = appUser.UserName,
SignIn = result
......@@ -64,15 +64,13 @@ namespace IoTSharp.Hub.Controllers
}
else
{
return Unauthorized(new { code = ApiCode.LoginError, msg = "Unauthorized", data = result });
return Unauthorized(new { code = ApiCode.LoginError, msg = "Unauthorized", data = result });
}
}
catch (Exception ex)
{
return this.ExceptionRequest(ex);
return this.ExceptionRequest(ex);
}
}
/// <summary>
......@@ -121,34 +119,5 @@ namespace IoTSharp.Hub.Controllers
return actionResult;
}
public class LoginResult
{
public string Token { get; set; }
public string UserName { get; set; }
public Microsoft.AspNetCore.Identity.SignInResult SignIn { get; set; }
public bool Succeeded { get; set; }
}
public class LoginDto
{
[Required]
public string Password { get; set; }
[Required]
public string Email { get; set; }
}
public class RegisterDto
{
[Required]
public string Email { get; set; }
[Required]
public string CustomerName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "PASSWORD_MIN_LENGTH", MinimumLength = 6)]
public string Password { get; set; }
}
}
}
\ No newline at end of file
......@@ -24,6 +24,7 @@ namespace IoTSharp.Hub.Controllers
private readonly IConfiguration _configuration;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ApplicationDBInitializer _dBInitializer;
public InstallerController(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
......@@ -50,7 +51,6 @@ namespace IoTSharp.Hub.Controllers
{
return this.ExceptionRequest(ex);
}
}
private InstanceDto GetInstanceDto()
......@@ -60,7 +60,7 @@ namespace IoTSharp.Hub.Controllers
[AllowAnonymous]
[HttpPost]
public ActionResult<InstanceDto> Install([FromBody] InstallDto model)
public async Task<ActionResult<InstanceDto>> Install([FromBody] InstallDto model)
{
ActionResult<InstanceDto> actionResult = NoContent();
try
......@@ -68,17 +68,17 @@ namespace IoTSharp.Hub.Controllers
if (!_context.Relationship.Any())
{
_dBInitializer.SeedRole();
_dBInitializer.SeedUser(model);
await _dBInitializer.SeedUserAsync(model);
actionResult = Ok(GetInstanceDto());
}
else
{
actionResult= BadRequest(new { code = ApiCode.AlreadyExists, msg = "Already installed", data = GetInstanceDto() });
actionResult = BadRequest(new { code = ApiCode.AlreadyExists, msg = "Already installed", data = GetInstanceDto() });
}
}
catch (Exception ex)
{
actionResult= this.ExceptionRequest(ex);
actionResult = this.ExceptionRequest(ex);
}
return actionResult;
}
......@@ -88,6 +88,7 @@ namespace IoTSharp.Hub.Controllers
public string Version { get; internal set; }
public bool Installed { get; internal set; }
}
public class InstallDto
{
[Required]
......
......@@ -7,33 +7,59 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using IoTSharp.Hub.Data;
using Microsoft.AspNetCore.Authorization;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace IoTSharp.Hub.Controllers
{
[Route("api/[controller]")]
[Authorize]
[ApiController]
public class TenantsController : ControllerBase
{
private readonly ApplicationDbContext _context;
private ApplicationDbContext _context;
private ILogger _logger;
private readonly UserManager<IdentityUser> _userManager;
private readonly IConfiguration _configuration;
private readonly SignInManager<IdentityUser> _signInManager;
public TenantsController(ApplicationDbContext context)
public TenantsController(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<TenantsController> logger, ApplicationDbContext context
)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_context = context;
}
[Authorize(Roles =nameof(UserRole.TenantAdmin))]
//[AllowAnonymous]
// GET: api/Tenants
/// <summary>
/// Only for SystemAdmin
/// </summary>
/// <returns></returns>
[Authorize(Roles = nameof(UserRole.SystemAdmin))]
[HttpGet]
public async Task<ActionResult<IEnumerable<Tenant>>> GetTenant()
{
return await _context.Tenant.ToListAsync();
var clamis = await _userManager.GetClaimsAsync(await _userManager.GetUserAsync(this.User));
var rows = await _userManager.GetRolesAsync(await _userManager.GetUserAsync(this.User));
return await _context.Tenant.ToListAsync();
}
/// <summary>
/// Normal user can use
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[Authorize(Roles = nameof(UserRole.NormalUser))]
// GET: api/Tenants/5
[HttpGet("{id}")]
public async Task<ActionResult<Tenant>> GetTenant(Guid id)
{
var _jwt = this.GetJwtSecurityToken();
var tenant = await _context.Tenant.FindAsync(id);
if (tenant == null)
......@@ -43,6 +69,7 @@ namespace IoTSharp.Hub.Controllers
return tenant;
}
[Authorize(Roles = nameof(UserRole.TenantAdmin))]
// PUT: api/Tenants/5
[HttpPut("{id}")]
......@@ -73,6 +100,7 @@ namespace IoTSharp.Hub.Controllers
return NoContent();
}
[Authorize(Roles = nameof(UserRole.SystemAdmin))]
// POST: api/Tenants
[HttpPost]
......@@ -83,6 +111,7 @@ namespace IoTSharp.Hub.Controllers
return CreatedAtAction("GetTenant", new { id = tenant.Id }, tenant);
}
[Authorize(Roles = nameof(UserRole.SystemAdmin))]
// DELETE: api/Tenants/5
[HttpDelete("{id}")]
......@@ -105,4 +134,4 @@ namespace IoTSharp.Hub.Controllers
return _context.Tenant.Any(e => e.Id == id);
}
}
}
}
\ No newline at end of file
......@@ -13,7 +13,6 @@ namespace IoTSharp.Hub.Data
{
public class ApplicationDBInitializer
{
private readonly RoleManager<IdentityRole> _role;
private ApplicationDbContext _context;
......@@ -21,6 +20,7 @@ namespace IoTSharp.Hub.Data
private readonly UserManager<IdentityUser> _userManager;
private readonly IConfiguration _configuration;
private readonly SignInManager<IdentityUser> _signInManager;
public ApplicationDBInitializer(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
......@@ -35,6 +35,7 @@ namespace IoTSharp.Hub.Data
_context = context;
_role = role;
}
public void SeedRole()
{
var roles = new IdentityRole[]{new IdentityRole(nameof(UserRole.Anonymous))
......@@ -49,7 +50,8 @@ namespace IoTSharp.Hub.Data
});
_context.SaveChanges();
}
public void SeedUser(InstallDto model)
public async Task SeedUserAsync(InstallDto model)
{
var tenant = _context.Tenant.FirstOrDefault(t => t.EMail == model.TenantEMail);
var customer = _context.Customer.FirstOrDefault(t => t.Email == model.CustomerEMail);
......@@ -62,9 +64,9 @@ namespace IoTSharp.Hub.Data
tenant.Customers.Add(customer);
_context.Tenant.Add(tenant);
_context.Customer.Add(customer);
_context.SaveChanges();
await _context.SaveChangesAsync();
}
IdentityUser user = _userManager.FindByEmailAsync(model.Email).GetAwaiter().GetResult();
IdentityUser user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
user = new IdentityUser
......@@ -73,19 +75,18 @@ namespace IoTSharp.Hub.Data
UserName = model.Email,
PhoneNumber = model.PhoneNumber
};
var result = _userManager.CreateAsync(user, model.Password).GetAwaiter().GetResult();
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_signInManager.SignInAsync(user, false);
_signInManager.UserManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, model.Email));
_signInManager.UserManager.AddClaimAsync(user, new Claim(IoTSharpClaimTypes.Customer, customer.Id.ToString()));
_signInManager.UserManager.AddClaimAsync(user, new Claim(IoTSharpClaimTypes.Tenant, tenant.Id.ToString()));
_signInManager.UserManager.AddToRolesAsync(user, new[] {
nameof(UserRole.Anonymous),
nameof(UserRole.NormalUser),
nameof(UserRole.CustomerAdmin),
nameof(UserRole.TenantAdmin),
nameof(UserRole.SystemAdmin)});
await _signInManager.SignInAsync(user, false);
await _signInManager.UserManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, model.Email));
await _signInManager.UserManager.AddClaimAsync(user, new Claim(IoTSharpClaimTypes.Customer, customer.Id.ToString()));
await _signInManager.UserManager.AddClaimAsync(user, new Claim(IoTSharpClaimTypes.Tenant, tenant.Id.ToString()));
await _signInManager.UserManager.AddToRoleAsync(user, nameof(UserRole.Anonymous));
await _signInManager.UserManager.AddToRoleAsync(user, nameof(UserRole.CustomerAdmin));
await _signInManager.UserManager.AddToRoleAsync(user, nameof(UserRole.TenantAdmin));
await _signInManager.UserManager.AddToRoleAsync(user, nameof(UserRole.SystemAdmin));
await _signInManager.UserManager.AddToRoleAsync(user, nameof(UserRole.Anonymous));
}
}
var rship = new Relationship
......@@ -95,7 +96,7 @@ namespace IoTSharp.Hub.Data
Tenant = _context.Tenant.Find(tenant.Id)
};
_context.Add(rship);
_context.SaveChanges();
await _context.SaveChangesAsync();
}
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace IoTSharp.Hub.Dtos
{
public class TokenEntity
{
public string access_token { get; set; }
public int expires_in { get; set; }
}
public class LoginResult
{
public string UserName { get; set; }
public Microsoft.AspNetCore.Identity.SignInResult SignIn { get; set; }
public bool Succeeded { get; set; }
public TokenEntity Token { get; set; }
}
public class LoginDto
{
[Required]
public string Password { get; set; }
[Required]
public string Email { get; set; }
}
public class RegisterDto
{
[Required]
public string Email { get; set; }
[Required]
public string CustomerName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "PASSWORD_MIN_LENGTH", MinimumLength = 6)]
public string Password { get; set; }
}
}
\ No newline at end of file
using HealthChecks.UI.Client;
using IoTSharp.Hub.Data;
using IoTSharp.Hub.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
......
using IoTSharp.Hub.Data;
using IoTSharp.Hub.Dtos;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
......@@ -17,19 +19,21 @@ namespace IoTSharp.Hub
{
public static class TokenExtension
{
static byte[] symmetricKeyBytes;
static SymmetricSecurityKey symmetricKey;
static SigningCredentials signingCredentials;
static TokenValidationParameters tokenValidationParams;
static TimeSpan _expire;
static string _issuer;
static string _audience;
private static byte[] symmetricKeyBytes;
private static SymmetricSecurityKey symmetricKey;
private static SigningCredentials signingCredentials;
private static TokenValidationParameters tokenValidationParams;
private static TimeSpan _expire;
private static string _issuer;
private static string _audience;
//Construct our JWT authentication paramaters then inject the parameters into the current TokenBuilder instance
// If injecting an RSA key for signing use this method
// Be weary of common jwt trips: https://trustfoundry.net/jwt-hacking-101/ and https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/
//public static void ConfigureJwtAuthentication(this IServiceCollection services, RSAParameters rsaParams)
public static void ConfigureJwtAuthentication(this IServiceCollection services, string issuer, string audience, string key, TimeSpan expire)
{
// JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
symmetricKeyBytes = Encoding.ASCII.GetBytes(key);
symmetricKey = new SymmetricSecurityKey(symmetricKeyBytes);
signingCredentials = new SigningCredentials(symmetricKey, SecurityAlgorithms.HmacSha256);
......@@ -37,7 +41,7 @@ namespace IoTSharp.Hub
if (_expire.TotalMinutes < 60) expire = TimeSpan.FromMinutes(60);
_issuer = issuer ?? "iotsharp.net";
_audience = audience ?? _issuer;
tokenValidationParams = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
......@@ -52,10 +56,10 @@ namespace IoTSharp.Hub
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = tokenValidationParams;
#if PROD || UAT
options.IncludeErrorDetails = false;
......@@ -64,7 +68,8 @@ namespace IoTSharp.Hub
#endif
});
}
public static async Task<string> GenerateJwtTokenAsync(this UserManager<IdentityUser> manager, IdentityUser user)
public static async Task<TokenEntity> GenerateJwtTokenAsync(this UserManager<IdentityUser> manager, IdentityUser user)
{
var roles = await manager.GetRolesAsync(user);
var claims = new List<Claim>
......@@ -85,8 +90,29 @@ namespace IoTSharp.Hub
var head = new JwtHeader();
var jwt = new JwtSecurityToken(tokenValidationParams.ValidIssuer, tokenValidationParams.ValidAudience, claims, DateTime.UtcNow, DateTime.Now.AddMinutes(_expire.TotalMinutes), signingCredentials);
jwt.Payload.AddClaims(claims.ToArray());
return new JwtSecurityTokenHandler().WriteToken(jwt);
var response = new TokenEntity
{
access_token = new JwtSecurityTokenHandler().WriteToken(jwt),
expires_in = (int)_expire.TotalSeconds
};
return response;
}
public static JwtSecurityToken GetJwtSecurityToken(this ControllerBase controller)
{
return controller.Request.GetJwtSecurityToken();
}
public static Claim GetClaim(this JwtSecurityToken jwt, string key)
{
return jwt.Payload.Claims.FirstOrDefault(c => c.Type == key);
}
public static IEnumerable<Claim> GetClaims(this JwtSecurityToken jwt)
{
return jwt.Payload.Claims;
}
public static JwtSecurityToken GetJwtSecurityToken(this HttpRequest httpRequest)
{
JwtSecurityToken result = null;
......@@ -118,13 +144,15 @@ namespace IoTSharp.Hub
}
return result;
}
public static string GetUserId(this JwtSecurityToken jwtSecurityToken)
{
return jwtSecurityToken.Payload["userid"] as string;
}
public static string GetPayloadValue(this JwtSecurityToken jwtSecurityToken, string Key)
{
return jwtSecurityToken.Payload[Key] as string;
}
}
}
}
\ No newline at end of file
......@@ -47,4 +47,5 @@
<PackageReference Include="QuartzHostedService" Version="0.0.3" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties appsettings_1Development_1json__JSONSchema="http://json.schemastore.org/bungee-plugin" /></VisualStudio></ProjectExtensions>
</Project>
\ No newline at end of file
......@@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using NSwag.AspNetCore;
using System;
using System.IdentityModel.Tokens.Jwt;
......@@ -25,9 +24,11 @@ namespace IoTSharp.Hub
public Startup(IConfiguration configuration)
{
Configuration = configuration;
AppSettings = Configuration.Get<AppSettings>();
}
public IConfiguration Configuration { get; }
public AppSettings AppSettings { get; }
public IConfiguration Configuration { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
......@@ -39,6 +40,8 @@ namespace IoTSharp.Hub
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.Configure<AppSettings>(Configuration);
services.AddLogging(loggingBuilder => loggingBuilder.AddConsole());
services.AddIoTSharpHub(Configuration);
......@@ -46,16 +49,10 @@ namespace IoTSharp.Hub
services.AddIdentity<IdentityUser, IdentityRole>()
.AddRoles<IdentityRole>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultTokenProviders()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
services.ConfigureJwtAuthentication(Configuration["JwtIssuer"], Configuration["JwtAudience"], Configuration["JwtKey"],TimeSpan.FromDays( Convert.ToInt32(Configuration["JwtExpireDays"])));
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
});
services.ConfigureJwtAuthentication(Configuration["JwtIssuer"], Configuration["JwtAudience"], Configuration["JwtKey"], TimeSpan.FromDays(Convert.ToInt32(Configuration["JwtExpireDays"])));
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
......@@ -85,19 +82,16 @@ namespace IoTSharp.Hub
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
// app.UseHsts();
}
app.UseAuthentication();
app.UseMvc();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册