临沂做网站wyjzgzs,无锡百度关键词推广,网站的规划方案,专业模板网站制作哪家好GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述#xff0c;使得客户端能够准确地获得它需要的数据#xff0c;而且没有任何冗余#xff0c;也让 API 更容易地随着时间推移而演进#xff0c… GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述使得客户端能够准确地获得它需要的数据而且没有任何冗余也让 API 更容易地随着时间推移而演进还能用于构建强大的开发者工具。 ——出自 https://graphql.cn由于HotChocklate是是基于asp.net core框架所以授权策略与原生的asp.net core mvc项目大同小异都是通过固定角色自定义策略等方式来进行的。下面的例子就是通过一个自定义策略的例子来进行的。并且授权是在实体类和实体类的属性上的而不是像之前在Controller的Action上对应的是一个api的url。看实例了解详情添加Nuget包HotChocolate.AspNetCoreHotChocolate.DataHotChocolate.Data.EntityFrameworkHotChocolate.AspNetCore.Authorization权限类namespace GraphQLDemo02
{/// summary/// 用户或角色或其他凭据实体/// /summarypublic class Permission{/// summary/// 用户或角色或其他凭据名称/// /summarypublic virtual string Name{ get; set; }/// summary/// 请求Url/// /summarypublic virtual string Url{ get; set; }}
}
创建自定义策略处理类using Microsoft.AspNetCore.Authorization;
using System.Threading.Tasks;
using System;namespace GraphQLDemo02
{/// summary/// 权限授权Handler/// /summarypublic class PermissionHandler : AuthorizationHandlerPermissionRequirement{/// summary/// 验证权限/// /summary/// param namecontext/param/// param namerequirement/param/// returns/returnsprotected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{//这里可以过滤属性授权Console.WriteLine(context.Resource.GetType().GetProperty(Path).GetValue(context.Resource));//是否经过验证var isAuthenticated context?.User?.Identity?.IsAuthenticated;if (isAuthenticated.HasValue isAuthenticated.Value){context.Succeed(requirement);}else{context.Fail();}return Task.CompletedTask;}}
}
AuthorizationRequirement类using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System;namespace GraphQLDemo02
{/// summary/// 必要参数类/// /summarypublic class PermissionRequirement : IAuthorizationRequirement{ /// summary/// 认证授权类型/// /summarypublic string ClaimType { internal get; set; }/// summary/// 发行人/// /summarypublic string Issuer { get; set; }/// summary/// 订阅人/// /summarypublic string Audience { get; set; }/// summary/// 过期时间/// /summarypublic TimeSpan Expiration { get; set; }/// summary/// 签名验证/// /summarypublic SigningCredentials SigningCredentials { get; set; } /// summary/// 构造/// /summary/// param namedeniedAction拒约请求的url/param/// param namepermissions权限集合/param/// param nameclaimType声明类型/param/// param nameissuer发行人/param/// param nameaudience订阅人/param/// param namesigningCredentials签名验证实体/parampublic PermissionRequirement(string claimType, string issuer, string audience, SigningCredentials signingCredentials, TimeSpan expiration){ClaimType claimType; Issuer issuer;Audience audience;Expiration expiration;SigningCredentials signingCredentials;}}
}
Token生成类using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;namespace GraphQLDemo02
{public class JwtToken{/// summary/// 获取基于JWT的Token/// /summary/// param nameusername/param/// returns/returnspublic static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement){var now DateTime.UtcNow;var jwt new JwtSecurityToken(issuer: permissionRequirement.Issuer,audience: permissionRequirement.Audience,claims: claims,notBefore: now,expires: now.Add(permissionRequirement.Expiration),signingCredentials: permissionRequirement.SigningCredentials);var encodedJwt new JwtSecurityTokenHandler().WriteToken(jwt);var response new{Status true,access_token encodedJwt,expires_in permissionRequirement.Expiration.TotalMilliseconds,token_type Bearer};return response;}}
}Starup.csusing Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Security.Claims;
using System.Text;
using Microsoft.EntityFrameworkCore;namespace GraphQLDemo02
{public class Startup{public IConfiguration Configuration { get; }public Startup(IConfiguration configuration){Configuration configuration;}public void ConfigureServices(IServiceCollection services){ services.AddPooledDbContextFactoryAdventureWorks2016Context((services, options) options.UseSqlServer(Configuration.GetConnectionString(ConnectionString)).UseLoggerFactory(services.GetRequiredServiceILoggerFactory())).AddGraphQLServer().AddAuthorization().AddQueryTypeQuery().AddFiltering().AddSorting().AddProjections();AddAuth(services);}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseAuthentication();app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints {endpoints.MapGraphQL();});}void AddAuth(IServiceCollection services){//读取配置文件var audienceConfig Configuration.GetSection(Audience);var symmetricKeyAsBase64 audienceConfig[Secret];var keyByteArray Encoding.ASCII.GetBytes(symmetricKeyAsBase64);var signingKey new SymmetricSecurityKey(keyByteArray);var tokenValidationParameters new TokenValidationParameters{ValidateIssuerSigningKey true,IssuerSigningKey signingKey,ValidateIssuer true,ValidIssuer audienceConfig[Issuer],ValidateAudience true,ValidAudience audienceConfig[Audience],ValidateLifetime true,ClockSkew TimeSpan.Zero,RequireExpirationTime true,};var signingCredentials new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);//如果第三个参数是ClaimTypes.Role上面集合的每个元素的Name为角色名称如果ClaimTypes.Name即上面集合的每个元素的Name为用户名var permissionRequirement new PermissionRequirement( ClaimTypes.Role,audienceConfig[Issuer],audienceConfig[Audience],signingCredentials,expiration: TimeSpan.FromSeconds(1000000)//设置Token过期时间);services.AddAuthorization(options {options.AddPolicy(Permission, policy policy.AddRequirements(permissionRequirement));}).AddAuthentication(options {options.DefaultAuthenticateScheme JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o {//不使用httpso.RequireHttpsMetadata false;o.TokenValidationParameters tokenValidationParameters;});//注入授权Handlerservices.AddSingletonIAuthorizationHandler, PermissionHandler();services.AddSingleton(permissionRequirement);}}
}Query.csusing HotChocolate;
using HotChocolate.Data;
using HotChocolate.Types;
using System;
using System.Linq;
using System.Security.Claims;namespace GraphQLDemo02
{ public class Query{[UseDbContext(typeof(AdventureWorks2016Context))][UseOffsetPaging][UseProjection][UseFiltering][UseSorting]public IQueryableProduct GetProducts([ScopedService] AdventureWorks2016Context context){return context.Products;}[UseDbContext(typeof(AdventureWorks2016Context))][UsePaging][UseProjection][UseFiltering][UseSorting]public IQueryablePerson GetPersons([ScopedService] AdventureWorks2016Context context){return context.People;}public TokenModel Login(string username, string password, [Service] PermissionRequirement requirement){Console.WriteLine(username);var isValidated username gsw password 111111;if (!isValidated){return new TokenModel(){Result false,Message 认证失败};}else{//如果是基于用户的授权策略这里要添加用户;如果是基于角色的授权策略这里要添加角色var claims new Claim[] {new Claim(ClaimTypes.Name, username),new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(200000).ToString())};var token JwtToken.BuildJwtToken(claims, requirement);return new TokenModel(){Result true,Data token.access_token};}} }
}
HotChocklate的验证是通过在实体类或实体类的属性上加自定义策略来对数据进行权限控制所以下面的例子是加在实体类上全部属性进行授权验证。Product.cs [HotChocolate.AspNetCore.Authorization.Authorize(Policy Permission)]public partial class Product{//此处略n多行}
Person.cs [Authorize(Policy Permission)]public partial class Person{//此处略n多行}
运行结果未验证登录拿到token后在header上追加验证token信息再次访问成功获取数据