当前位置:网站首页>Graphql: authentication and authorization

Graphql: authentication and authorization

2020-12-07 12:46:05 osc_ wz0c6jgl

GraphQL Is a API Our query language is also a runtime for your data query .GraphQL To you API The data in provides a complete set of easy to understand descriptions , Enable the client to accurately obtain the data it needs , And there's no redundancy , Also let API Easier to evolve over time , It can also be used to build powerful developer tools .

                                  —— come from  https://graphql.cn

because HotChocklate It's based on asp.net core frame , So the authorization policy and the native asp.net core mvc The project is similar with little difference , All through fixed roles , Custom strategy and other ways to do . The following example is done through an example of a custom policy .

And authorization is on the entity class and its properties , Not like before Controller Of Action On , It corresponds to a api Of url.

Look at examples for details :

add to Nuget package

HotChocolate.AspNetCore

HotChocolate.Data

HotChocolate.Data.EntityFramework

HotChocolate.AspNetCore.Authorization

Permission class

namespace GraphQLDemo02
{
    /// <summary>
    ///  User or role or other credential entity 
    /// </summary>
    public class Permission
    {
        /// <summary>
        ///  User or role or other credential name 
        /// </summary>
        public virtual string Name
        { get; set; }
        /// <summary>
        ///  request Url
        /// </summary>
        public virtual string Url
        { get; set; }
    }
}

Create custom policy handling



using Microsoft.AspNetCore.Authorization;
using System.Threading.Tasks;
using System;


namespace GraphQLDemo02
{
    /// <summary>
    ///  Authority authorization Handler
    /// </summary>
    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        /// <summary>
        ///  Verify permissions 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requirement"></param>
        /// <returns></returns>
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
            // Here you can filter attribute Authorization 
            Console.WriteLine(context.Resource.GetType().GetProperty("Path").GetValue(context.Resource));
            // Is it verified 
            var isAuthenticated = context?.User?.Identity?.IsAuthenticated;
            if (isAuthenticated.HasValue && isAuthenticated.Value)
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
            return Task.CompletedTask;
        }
    }
}

AuthorizationRequirement class

using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System;


namespace GraphQLDemo02
{


    /// <summary>
    ///  Necessary parameter class 
    /// </summary>
    public class PermissionRequirement : IAuthorizationRequirement
    { 
        /// <summary>
        ///  Authentication authorization type 
        /// </summary>
        public string ClaimType { internal get; set; }
       
        /// <summary>
        ///  The issuer 
        /// </summary>
        public string Issuer { get; set; }
        /// <summary>
        ///  Subscribe to the people 
        /// </summary>
        public string Audience { get; set; }
        /// <summary>
        ///  Expiration time 
        /// </summary>
        public TimeSpan Expiration { get; set; }
        /// <summary>
        ///  Signature verification 
        /// </summary>
        public SigningCredentials SigningCredentials { get; set; }       
        /// <summary>
        ///  structure 
        /// </summary>
        /// <param name="deniedAction"> Refusing a contract request url</param>
        /// <param name="permissions"> Privilege set </param>
        /// <param name="claimType"> Declaration type </param>
        /// <param name="issuer"> The issuer </param>
        /// <param name="audience"> Subscribe to the people </param>
        /// <param name="signingCredentials"> Signature verification entity </param>
        public PermissionRequirement(string claimType, string issuer, string audience, SigningCredentials signingCredentials, TimeSpan expiration)
        {
            ClaimType = claimType;                
            Issuer = issuer;
            Audience = audience;
            Expiration = expiration;
            SigningCredentials = signingCredentials;
        }
    }
}

Token Generating classes

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;


namespace GraphQLDemo02
{
    public class JwtToken
    {
        /// <summary>
        ///  Access based on JWT Of Token
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        public 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.cs

using 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.AddPooledDbContextFactory<AdventureWorks2016Context>(
              (services, options) => options
              .UseSqlServer(Configuration.GetConnectionString("ConnectionString"))
              .UseLoggerFactory(services.GetRequiredService<ILoggerFactory>()))
              .AddGraphQLServer()
              .AddAuthorization()
              .AddQueryType<Query>()
              .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)
        {
            // Read configuration file 
            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);


            // If the third parameter , yes ClaimTypes.Role, Of each element of the set above Name For the role name , If ClaimTypes.Name, Of each element of the set above Name Username 
            var permissionRequirement = new PermissionRequirement(              
                ClaimTypes.Role,
                audienceConfig["Issuer"],
                audienceConfig["Audience"],
                signingCredentials,
                expiration: TimeSpan.FromSeconds(1000000)// Set up Token Expiration time 
                );


            services.AddAuthorization(options =>
            {
                options.AddPolicy("Permission", policy => policy.AddRequirements(permissionRequirement));
            }).
            AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
            {
                // Don't use https
                o.RequireHttpsMetadata = false;
                o.TokenValidationParameters = tokenValidationParameters;


            });
            // Injection authorization Handler
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
            services.AddSingleton(permissionRequirement);
        }
    }
}


Query.cs

using 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 IQueryable<Product> GetProducts([ScopedService] AdventureWorks2016Context context)
        {
            return context.Products;
        }


        [UseDbContext(typeof(AdventureWorks2016Context))]
        [UsePaging]
        [UseProjection]
        [UseFiltering]
        [UseSorting]
        public IQueryable<Person> 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 = " Authentication failed "
                };
            }
            else
            {
                // If the policy is based on authorization , Here to add users ; If it's a role-based authorization policy , Here's to add a character 
                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 The verification is to control the authority of data by adding user-defined policies on entity class or attribute of entity class , So the following example is added to the entity class , All attributes are authorized to verify .

Product.cs

    [HotChocolate.AspNetCore.Authorization.Authorize(Policy = "Permission")]
    public partial class Product
    {
       // Here slightly n Multiple lines 
    }

Person.cs

    [Authorize(Policy = "Permission")]
    public partial class Person
    {
      // Here slightly n Multiple lines 
    }

Running results :

Not verified

Sign in

Get token after , stay header Add verification on token Information , Revisit , Data acquired successfully

版权声明
本文为[osc_ wz0c6jgl]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/20201207123642218l.html