Former-commit-id: 260302b5cd23f4450e86c1560f29061a85c0d6ce
TangShanKaiPing
wanggang 6 years ago
parent a027cc08e0
commit 28f26eceed

@ -1,14 +1,14 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.Extensions
{
@ -22,23 +22,33 @@ namespace Infrastructure.Extensions
httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, new AuthenticationProperties { IsPersistent = rememberMe });
}
public static void SignIn(this HttpContext httpContext, string userName, bool rememberMe, IConfiguration cfg)
public static void SignIn(this HttpContext httpContext, string userName, bool rememberMe, IConfiguration cfg, DateTime expires)
{
var token = httpContext.GetToken(userName, rememberMe, cfg, expires);
httpContext.Response.Cookies.Delete("jwt");
httpContext.Response.Cookies.Append("jwt", token);
}
public static string GetToken(this HttpContext httpContext, string userName, bool rememberMe, IConfiguration cfg, DateTime expires)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(cfg["jwt:key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) };
//claims.AddRange(roles.Select(o => new Claim(ClaimTypes.Role, o)).ToList());
var token = new JwtSecurityToken(
issuer: cfg["jwt:issuer"],
audience: cfg["jwt:audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(rememberMe ? 3600 : 3),
expires: expires,
signingCredentials: creds);
var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
httpContext.Response.Cookies.Delete("jwt");
httpContext.Response.Cookies.Append("jwt", tokenText);
return tokenText;
}
public static JwtSecurityToken ReadToken(this HttpContext httpContext, string token)
{
return new JwtSecurityTokenHandler().ReadJwtToken(token);
}
}
}

@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="CS-Script.Core" Version="1.2.3.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.1.1" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

@ -19,6 +19,7 @@ using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.SignalR;
@ -31,14 +32,11 @@ using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Diagnostics;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;
@ -117,11 +115,30 @@ namespace Infrastructure.Web
return localizer;
};
});
services.AddControllers().AddNewtonsoftJson(o =>
services.AddApiVersioning(o =>
{
o.SerializerSettings.ContractResolver = new DefaultContractResolver();
o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
o.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader()
//,new QueryStringApiVersionReader()
//,new HeaderApiVersionReader()
);
});
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
//options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404";
})
.AddNewtonsoftJson(o =>
{
o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
services.Configure<RequestLocalizationOptions>(o =>
{
var supportedCultures = new[]
@ -223,7 +240,7 @@ namespace Infrastructure.Web
},
OnMessageReceived = context =>
{
if(!context.Request.IsStatic())
if (!context.Request.IsStatic())
{
Debug.WriteLine(context.Request.Path);
if (context.Request.Query.ContainsKey("access_token"))

@ -205,16 +205,10 @@ namespace UserCenter.Controllers
}
else
{
//var userPermissions = this._userRepo.ReadOnlyTable().Where(o => o.UserName == userName)
// .SelectMany(o => o.UserRoles)
// .Select(o => o.Role)
// .SelectMany(o => o.RolePermissions)
// .Select(o => o.Permission.Number)
// .ToList();
HttpContext.SignIn(model.UserName, model.RememberMe, _cfg);
HttpContext.SignIn(model.UserName, model.RememberMe, _cfg, DateTime.Now.AddDays(1));
if (string.IsNullOrEmpty(returnUrl))
{
returnUrl = Url.Action("Index","Home");
returnUrl = Url.Action("Index", "Home");
}
ViewBag.Url = returnUrl;
var urls = new List<string>();

@ -0,0 +1,143 @@
using Application.Domain.Entities;
using Application.Models;
using Infrastructure.Data;
using Infrastructure.Extensions;
using Infrastructure.Security;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Linq;
using System.Net.Mime;
using System.Security.Claims;
namespace UserCenter.Controllers
{
[ApiVersion("1.0")]
[Route("api/[controller]/[action]")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
[ApiController]
[Produces(MediaTypeNames.Application.Json)]
public class TokenController : ControllerBase
{
private readonly IConfiguration _cfg;
private readonly IRepository<User> _userRepo;
private readonly IEncryptionService _encryptionService;
public TokenController(IConfiguration cfg,
IRepository<User> userRepo,
IEncryptionService encryptionService)
{
this._cfg = cfg;
this._userRepo = userRepo;
this._encryptionService = encryptionService;
}
[HttpPost]
public ActionResult GetToken([FromBody]LoginModel model)
{
var success = false;
try
{
var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == model.UserName);
if (user == null)
{
ModelState.AddModelError("", "用户名或密码错误");
}
else
{
var maxAccessFailedCount = this._cfg.GetValue<int>("MaxFailedAccessAttemptsBeforeLockout");
var lockoutEndMinutes = this._cfg.GetValue<int>("DefaultAccountLockoutMinutes");
if (user.LockoutEnabled)//对已启用登录锁定的用户,如果当前登录时间超出锁定时间,先解除锁定状态
{
if (user.LockoutEnd.HasValue && DateTime.UtcNow > user.LockoutEnd)
{
user.LockoutEnd = null;
user.AccessFailedCount = 0;
this._userRepo.SaveChanges();
}
}
if (user.LockoutEnabled)//对启用登录锁定的用户进行验证
{
if (user.LockoutEnd.HasValue == false)
{
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp))
{
user.LockoutEnd = null;
user.AccessFailedCount = 0;
success = true;
}
else
{
user.AccessFailedCount += 1;
if (user.AccessFailedCount >= maxAccessFailedCount)
{
user.LockoutEnd = DateTime.UtcNow.AddMinutes(lockoutEndMinutes);
ModelState.AddModelError(nameof(model.UserName), $"用户被锁定,请于{user.LockoutEnd.Value.ToLocalTime().ToString("HH:mm")}后重试");
}
else
{
ModelState.AddModelError(nameof(model.UserName), $"密码错误,再错误{maxAccessFailedCount - user.AccessFailedCount}次后将锁定用户{lockoutEndMinutes}分钟");
}
}
this._userRepo.SaveChanges();
}
}
else//对未启用登录锁定的用户进行验证
{
if (user.PasswordHash == this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp))
{
success = true;
}
else
{
ModelState.AddModelError("", "用户名或密码错误");
}
}
}
if (success)
{
return Ok(new
{
AccessToken = Request.HttpContext.GetToken(model.UserName, false, _cfg, DateTime.Now.AddHours(_cfg.GetValue<double>("AccessTokenHours", 0.5))),
RefreshToken = Request.HttpContext.GetToken(model.UserName, false, _cfg, DateTime.Now.AddHours(_cfg.GetValue<double>("AccessTokenHours", 720))),
});
}
else
{
return BadRequest(ModelState);
}
}
catch (Exception ex)
{
ex.PrintStack();
return Problem(ex.Message);
}
}
[HttpPost]
public ActionResult RefreshToken([FromBody]string refreshToken)
{
try
{
var token = Request.HttpContext.ReadToken(refreshToken);
if (DateTime.UtcNow > token.ValidTo)
{
ModelState.AddModelError("", "已过期");
return BadRequest(ModelState);
}
var userName = token.Claims.FirstOrDefault(o => o.Type == ClaimTypes.Name).Value;
return Ok(new
{
AccessToken = Request.HttpContext.GetToken(userName, false, _cfg, DateTime.Now.AddHours(_cfg.GetValue<double>("AccessTokenHours", 0.5))),
RefreshToken = Request.HttpContext.GetToken(userName, false, _cfg, DateTime.Now.AddHours(_cfg.GetValue<double>("AccessTokenHours", 720))),
});
}
catch (Exception ex)
{
ex.PrintStack();
return Problem(ex.Message);
}
}
}
}

@ -12,6 +12,8 @@ namespace UserCenter
{
WebHost.CreateDefaultBuilder(args)
.Run<Startup>(new List<EFConfigurationValue> {
new EFConfigurationValue { Id = "AccessTokenHours", Value= "0.5"},
new EFConfigurationValue { Id = "RefreshToken", Value= "720"},
new EFConfigurationValue { Id = "MaxFailedAccessAttemptsBeforeLockout", Value= "5"},
new EFConfigurationValue { Id = "DefaultAccountLockoutMinutes", Value= "10"},
new EFConfigurationValue { Id = "CaptchaSeconds", Value= "60"},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0,viewport-fit=cover">
<title>网关</title>
</head>
<body>
<h1>网关</h1>
</body>
</html>
Loading…
Cancel
Save