public SignInUserCommand(AppDbContext dbContext, IJsonWebTokenService jsonWebTokenService, JsonWebTokenSettings jsonWebTokenSettings) { _dbContext = dbContext; _jsonWebTokenService = jsonWebTokenService; _jsonWebTokenSettings = jsonWebTokenSettings; }
public static JsonWebTokenSettings AddSecurity(this IServiceCollection services, IConfiguration configuration) { JsonWebTokenSettings jsonWebTokenSettings = new JsonWebTokenSettings( configuration["Authentication:JwtBearer:SecurityKey"], new TimeSpan(1, 0, 0, 0), configuration["Authentication:JwtBearer:Audience"], configuration["Authentication:JwtBearer:Issuer"] ); services.AddHash(10000, 128); services.AddCryptography("lin-cms-dotnetcore-cryptography"); services.AddJsonWebToken(jsonWebTokenSettings); return(jsonWebTokenSettings); }
private static JsonWebTokenSettings AddSecurity(this IServiceCollection services) { JsonWebTokenSettings jsonWebTokenSettings = new JsonWebTokenSettings( Appsettings.JwtBearer.SecurityKey, TimeSpan.FromMinutes(Appsettings.JwtBearer.Expires), Appsettings.JwtBearer.Audience, Appsettings.JwtBearer.Issuer ); services.AddHashService(); services.AddICryptographyService("Memoyu.Blog-cryptography"); services.AddJsonWebTokenService(jsonWebTokenSettings); return(jsonWebTokenSettings); }
/// <summary> /// 根据配置文件创建JsonWebTokenSettings /// 默认过期时间为1天 /// </summary> /// <param name="services">IServiceCollection</param> /// <returns>JsonWebTokenSettings</returns> public static JsonWebTokenSettings AddSecurity(this IServiceCollection services) { var jsonWebTokenSettings = new JsonWebTokenSettings( NpsEnvironment.NPS_AUTH_JWT_SECURITYKEY, new TimeSpan(NpsEnvironment.NPS_AUTH_JWT_EXPIRESIN.ToInt32OrDefault(15), 0, 0, 0), NpsEnvironment.NPS_AUTH_JWT_AUDIENCE, NpsEnvironment.NPS_AUTH_JWT_ISSUER ); services.AddHash(); services.AddCryptography(NpsEnvironment.NPS_AUTH_JWT_CRYPTOGRAPHY); services.AddJsonWebToken(jsonWebTokenSettings); return(jsonWebTokenSettings); }
public SecurityTests() { var services = new ServiceCollection(); services.AddSingleton <ICryptographyService>(_ => new CryptographyService(Guid.NewGuid().ToString())); _cryptographyService = services.BuildServiceProvider().GetService <ICryptographyService>(); services.AddSingleton <IHashService, HashService>(); _hashService = services.BuildServiceProvider().GetService <IHashService>(); var jsonWebTokenSettings = new JsonWebTokenSettings(Guid.NewGuid().ToString(), TimeSpan.FromHours(12)); services.AddSingleton <IJsonWebTokenService>(_ => new JsonWebTokenService(jsonWebTokenSettings)); _jsonWebTokenService = services.BuildServiceProvider().GetService <IJsonWebTokenService>(); }
public void ConfigureServices(IServiceCollection services) { services.AddContext(Configuration); services.AddCsRedisCore(Configuration); JsonWebTokenSettings jsonWebTokenSettings = services.AddSecurity(Configuration); #region AddJwtBearer services.AddAuthentication(opts => { opts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddCookie() .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { bool isIds4 = Configuration["Service:IdentityServer4"].ToBoolean(); if (isIds4) { //identityserver4 地址 也就是本项目地址 options.Authority = Configuration["Service:Authority"]; } options.RequireHttpsMetadata = Configuration["Service:UseHttps"].ToBoolean(); options.Audience = Configuration["Service:Name"]; options.TokenValidationParameters = new TokenValidationParameters { // The signing key must match! ValidateIssuerSigningKey = true, IssuerSigningKey = jsonWebTokenSettings.SecurityKey, // Validate the JWT Issuer (iss) claim ValidateIssuer = true, ValidIssuer = jsonWebTokenSettings.Issuer, // Validate the JWT Audience (aud) claim ValidateAudience = true, ValidAudience = jsonWebTokenSettings.Audience, // Validate the token expiry ValidateLifetime = true, // If you want to allow a certain amount of clock drift, set thatValidIssuer here //ClockSkew = TimeSpan.Zero }; //options.TokenValidationParameters = new TokenValidationParameters() //{ // ClockSkew = TimeSpan.Zero //偏移设置为了0s,用于测试过期策略,完全按照access_token的过期时间策略,默认原本为5分钟 //}; //使用Authorize设置为需要登录时,返回json格式数据。 options.Events = new JwtBearerEvents() { OnAuthenticationFailed = context => { //Token expired if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return(Task.CompletedTask); }, OnChallenge = context => { //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦 context.HandleResponse(); string message; ErrorCode errorCode; int statusCode = StatusCodes.Status401Unauthorized; if (context.Error == "invalid_token" && context.ErrorDescription == "The token is expired") { message = "令牌过期"; errorCode = ErrorCode.TokenExpired; statusCode = StatusCodes.Status422UnprocessableEntity; } else if (context.Error == "invalid_token" && context.ErrorDescription.IsNullOrEmpty()) { message = "令牌失效"; errorCode = ErrorCode.TokenInvalidation; } else { message = "请先登录" + context.ErrorDescription; //""认证失败,请检查请求头或者重新登录"; errorCode = ErrorCode.AuthenticationFailed; } context.Response.ContentType = "application/json"; context.Response.StatusCode = statusCode; context.Response.WriteAsync(new UnifyResponseDto(errorCode, message, context.HttpContext).ToString()); return(Task.FromResult(0)); } }; }) .AddGitHub(options => { options.ClientId = Configuration["Authentication:GitHub:ClientId"]; options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"]; options.Scope.Add("user:email"); options.ClaimActions.MapJsonKey(LinConsts.Claims.AvatarUrl, "avatar_url"); options.ClaimActions.MapJsonKey(LinConsts.Claims.HtmlUrl, "html_url"); //登录成功后可通过 authenticateResult.Principal.FindFirst(ClaimTypes.Uri)?.Value; 得到GitHub头像 options.ClaimActions.MapJsonKey(LinConsts.Claims.BIO, "bio"); options.ClaimActions.MapJsonKey(LinConsts.Claims.BlogAddress, "blog"); }) .AddQQ(options => { options.ClientId = Configuration["Authentication:QQ:ClientId"]; options.ClientSecret = Configuration["Authentication:QQ:ClientSecret"]; }) .AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, "码云", options => { options.ClientId = Configuration["Authentication:Gitee:ClientId"]; options.ClientSecret = Configuration["Authentication:Gitee:ClientSecret"]; options.ClaimActions.MapJsonKey("urn:gitee:avatar_url", "avatar_url"); options.ClaimActions.MapJsonKey("urn:gitee:blog", "blog"); options.ClaimActions.MapJsonKey("urn:gitee:bio", "bio"); options.ClaimActions.MapJsonKey("urn:gitee:html_url", "html_url"); //options.Scope.Add("projects"); //options.Scope.Add("pull_requests"); //options.Scope.Add("issues"); //options.Scope.Add("notes"); //options.Scope.Add("keys"); //options.Scope.Add("hook"); //options.Scope.Add("groups"); //options.Scope.Add("gists"); //options.Scope.Add("enterprises"); options.SaveTokens = true; }); #endregion services.AddAutoMapper(typeof(UserProfile).Assembly, typeof(PoemProfile).Assembly); services.AddCors(); #region Mvc services.AddControllers(options => { options.ValueProviderFactories.Add(new ValueProviderFactory()); //设置SnakeCase形式的QueryString参数 //options.Filters.Add<LogActionFilterAttribute>(); // 添加请求方法时的日志记录过滤器 options.Filters.Add <LinCmsExceptionFilter>(); // }) .AddNewtonsoftJson(opt => { opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:MM:ss"; // 设置自定义时间戳格式 opt.SerializerSettings.Converters = new List <JsonConverter>() { new LinCmsTimeConverter() }; // 设置下划线方式,首字母是小写 opt.SerializerSettings.ContractResolver = new DefaultContractResolver() { NamingStrategy = new SnakeCaseNamingStrategy() { //ProcessDictionaryKeys = true }, }; }) .ConfigureApiBehaviorOptions(options => { //options.SuppressConsumesConstraintForFormFileParameters = true; //SuppressUseValidationProblemDetailsForInvalidModelStateResponses; //自定义 BadRequest 响应 options.InvalidModelStateResponseFactory = context => { var problemDetails = new ValidationProblemDetails(context.ModelState); var resultDto = new UnifyResponseDto(ErrorCode.ParameterError, problemDetails.Errors, context.HttpContext); return(new BadRequestObjectResult(resultDto) { ContentTypes = { "application/json" } }); }; }); services.AddSwaggerGenNewtonsoftSupport(); #endregion services.AddDIServices(Configuration); #region Swagger //Swagger重写PascalCase,改成SnakeCase模式 services.TryAddEnumerable(ServiceDescriptor.Transient <IApiDescriptionProvider, ApiDescriptionProvider>()); //Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(options => { string ApiName = "LinCms.Web"; options.SwaggerDoc("v1", new OpenApiInfo() { Title = ApiName + RuntimeInformation.FrameworkDescription, Version = "v1", Contact = new OpenApiContact { Name = ApiName, Email = "*****@*****.**", Url = new Uri("https://www.cnblogs.com/igeekfan/") }, License = new OpenApiLicense { Name = ApiName + " 官方文档", Url = new Uri("https://luoyunchong.github.io/vovo-docs/dotnetcore/lin-cms/dotnetcore-start.html") } }); var security = new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference() { Id = JwtBearerDefaults.AuthenticationScheme, Type = ReferenceType.SecurityScheme } }, Array.Empty <string>() } }; options.AddSecurityRequirement(security); //添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。 options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", Name = "Authorization", //jwt默认的参数名称 In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); try { string xmlPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Startup).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(xmlPath, true); //实体层的xml文件名 string xmlEntityPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(IEntity).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(xmlEntityPath); //Dto所在类库 string applicationPath = Path.Combine(AppContext.BaseDirectory, $"{typeof(IApplicationService).Assembly.GetName().Name}.xml"); options.IncludeXmlComments(applicationPath); } catch (Exception ex) { Log.Logger.Warning(ex.Message); } options.AddServer(new OpenApiServer() { Url = "", Description = "v1" }); options.CustomOperationIds(apiDesc => { return(apiDesc.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null); }); }); #endregion //应用程序级别设置 services.Configure <FormOptions>(options => { //单个文件上传的大小限制为8 MB 默认134217728 应该是128MB options.MultipartBodyLengthLimit = 1024 * 1024 * 8; //8MB }); // 分布式事务一致性CAP services.AddCap(Configuration); services.Configure <ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); //之前请注入AddCsRedisCore,内部实现IDistributedCache接口 services.AddIpRateLimiting(Configuration); services.AddHealthChecks(); }
public static void AddJsonWebToken(this IServiceCollection services, JsonWebTokenSettings jsonWebTokenSettings) { services.AddSingleton(_ => jsonWebTokenSettings); services.AddSingleton <IJsonWebToken, JsonWebToken>(); }
public static void AddJwtBearer(this IServiceCollection services, IConfiguration Configuration) { JsonWebTokenSettings jsonWebTokenSettings = services.AddSecurity(Configuration); services.AddAuthentication(opts => { opts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddCookie() .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { bool isIds4 = Configuration["Service:IdentityServer4"].ToBoolean(); if (isIds4) { //identityserver4 地址 也就是本项目地址 options.Authority = Configuration["Service:Authority"]; } options.RequireHttpsMetadata = Configuration["Service:UseHttps"].ToBoolean(); options.Audience = Configuration["Service:Name"]; options.TokenValidationParameters = new TokenValidationParameters { // The signing key must match! ValidateIssuerSigningKey = true, IssuerSigningKey = jsonWebTokenSettings.SecurityKey, // Validate the JWT Issuer (iss) claim ValidateIssuer = true, ValidIssuer = jsonWebTokenSettings.Issuer, // Validate the JWT Audience (aud) claim ValidateAudience = true, ValidAudience = jsonWebTokenSettings.Audience, // Validate the token expiry ValidateLifetime = true, // If you want to allow a certain amount of clock drift, set thatValidIssuer here //ClockSkew = TimeSpan.Zero }; //options.TokenValidationParameters = new TokenValidationParameters() //{ // ClockSkew = TimeSpan.Zero //偏移设置为了0s,用于测试过期策略,完全按照access_token的过期时间策略,默认原本为5分钟 //}; //使用Authorize设置为需要登录时,返回json格式数据。 options.Events = new JwtBearerEvents() { OnAuthenticationFailed = context => { //Token expired if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return(Task.CompletedTask); }, OnChallenge = async context => { //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦 context.HandleResponse(); string message; ErrorCode errorCode; int statusCode = StatusCodes.Status401Unauthorized; if (context.Error == "invalid_token" && context.ErrorDescription == "The token is expired") { message = "令牌过期"; errorCode = ErrorCode.TokenExpired; statusCode = StatusCodes.Status422UnprocessableEntity; } else if (context.Error == "invalid_token" && context.ErrorDescription.IsNullOrEmpty()) { message = "令牌失效"; errorCode = ErrorCode.TokenInvalidation; } else { message = "请先登录 " + context.ErrorDescription; //""认证失败,请检查请求头或者重新登录"; errorCode = ErrorCode.AuthenticationFailed; } context.Response.ContentType = "application/json"; context.Response.StatusCode = statusCode; await context.Response.WriteAsync(new UnifyResponseDto(errorCode, message, context.HttpContext).ToString()); } }; }) .AddGitHub(options => { options.ClientId = Configuration["Authentication:GitHub:ClientId"]; options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"]; options.Scope.Add("user:email"); options.ClaimActions.MapJsonKey(LinConsts.Claims.AvatarUrl, "avatar_url"); options.ClaimActions.MapJsonKey(LinConsts.Claims.HtmlUrl, "html_url"); //登录成功后可通过 authenticateResult.Principal.FindFirst(ClaimTypes.Uri)?.Value; 得到GitHub头像 options.ClaimActions.MapJsonKey(LinConsts.Claims.BIO, "bio"); options.ClaimActions.MapJsonKey(LinConsts.Claims.BlogAddress, "blog"); }) .AddQQ(options => { options.ClientId = Configuration["Authentication:QQ:ClientId"]; options.ClientSecret = Configuration["Authentication:QQ:ClientSecret"]; }) .AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, "码云", options => { options.ClientId = Configuration["Authentication:Gitee:ClientId"]; options.ClientSecret = Configuration["Authentication:Gitee:ClientSecret"]; options.ClaimActions.MapJsonKey("urn:gitee:avatar_url", "avatar_url"); options.ClaimActions.MapJsonKey("urn:gitee:blog", "blog"); options.ClaimActions.MapJsonKey("urn:gitee:bio", "bio"); options.ClaimActions.MapJsonKey("urn:gitee:html_url", "html_url"); //options.Scope.Add("projects"); //options.Scope.Add("pull_requests"); //options.Scope.Add("issues"); //options.Scope.Add("notes"); //options.Scope.Add("keys"); //options.Scope.Add("hook"); //options.Scope.Add("groups"); //options.Scope.Add("gists"); //options.Scope.Add("enterprises"); options.SaveTokens = true; }); }
public JsonWebTokenService(JsonWebTokenSettings jsonWebTokenSettings) { JsonWebTokenSettings = jsonWebTokenSettings; }
/// <summary> /// 注入JWT /// </summary> /// <param name="services">IServiceCollection</param> public static void AddJwtBearer(this IServiceCollection services) { Log.Logger.Information("Initialize JwtBearer Start;"); Check.NotNull(services, nameof(services)); JsonWebTokenSettings jsonWebTokenSettings = services.AddSecurity(); // 开启Bearer认证 services.AddAuthentication(opts => { opts.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) // 添加JwtBearer服务 .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { //令牌验证参数 options.TokenValidationParameters = new TokenValidationParameters { //是否验证密钥 ValidateIssuerSigningKey = true, //密钥 IssuerSigningKey = jsonWebTokenSettings.SecurityKey, //是否验证发行人 ValidateIssuer = true, ValidIssuer = jsonWebTokenSettings.Issuer, //是否验证受众人 ValidateAudience = true, ValidAudience = jsonWebTokenSettings.Audience, //验证生命周期 ValidateLifetime = true, //过期时间 RequireExpirationTime = true, // 允许服务器时间偏移量300秒,即我们配置的过期时间加上这个允许偏移的时间值,才是真正过期的时间(过期时间 +偏移值)你也可以设置为0 //ClockSkew = TimeSpan.Zero }; //使用Authorize设置为需要登录时,返回json格式数据。 options.Events = new JwtBearerEvents() { //授权失败 OnAuthenticationFailed = context => { //Token expired if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return(Task.CompletedTask); }, //未授权 OnChallenge = async context => { //此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦 context.HandleResponse(); string message; StatusCode status; int statusCode = StatusCodes.Status401Unauthorized; if (context.Error == "invalid_token" && context.ErrorDescription == "The token is expired") { message = "令牌过期"; status = StatusCode.TokenExpired; statusCode = StatusCodes.Status422UnprocessableEntity; } else if (context.Error == "invalid_token" && string.IsNullOrWhiteSpace(context.ErrorDescription)) { message = "令牌失效"; status = StatusCode.TokenInvalidation; } else { message = "请先登录 " + context.ErrorDescription; //""认证失败,请检查请求头或者重新登录"; status = StatusCode.AuthenticationFailed; } context.Response.ContentType = "application/json"; context.Response.StatusCode = statusCode; await context.Response.WriteAsync(ExecuteResult.Error(message, status).ToJson()); } }; }); Log.Logger.Information("Initialize JwtBearer End;"); }