Getting Null from value using IOptionSnapshot<T> - c#

I'm trying to implement Azure App Configuration to my Application that uses the ASP.NET Boilerplate Framework. I'm following this tutorial but when I try to access my settings everything comes null. When the Startup.cs get executed I can see the values in the constructor but when I try to get them else where I get the null.
Program.cs:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((config) =>
{
// Retrieve the connection string
IConfiguration settings = config.Build();
string connectionString = settings.GetConnectionString("AppConfig");
// Load configuration from Azure App Configuration
config.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
// Load all keys that start with `TestApp:` and have no label
.Select("TestApp:*", LabelFilter.Null)
// Configure to reload configuration if the registered sentinel key is modified
.ConfigureRefresh(refreshOptions => refreshOptions.Register("TestApp:Settings:Sentinel", refreshAll: true));
}).Build();
})
.UseStartup<Startup>()
.Build();
}
}
Startup.cs:
public class Startup
{
private const string _defaultCorsPolicyName = "localhost";
private const string _apiVersion = "v1";
public IConfigurationRoot _appConfiguration;
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment env, IConfiguration configuration)
{
_appConfiguration = env.GetAppConfiguration();
Configuration = configuration; //Azure App Configuration
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//MVC
services.AddControllersWithViews(
options =>
{
options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
}
).AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
{
NamingStrategy = new CamelCaseNamingStrategy()
};
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddSignalR();
// Configure CORS for angular2 UI
services.AddCors(
options => options.AddPolicy(
_defaultCorsPolicyName,
builder => builder
.WithOrigins(
// App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
_appConfiguration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
)
);
options.DocInclusionPredicate((docName, description) => true);
// Define the BearerAuth scheme that's in use
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
});
services.AddAzureAppConfiguration();
// Bind configuration "TestApp:Settings" section to the Settings object
services.AddOptions();
services.Configure<Settings>(Configuration.GetSection("TestApp:Settings"));
// Configure Abp and Dependency Injection
return services.AddAbp<RptWebHostModule>(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.
app.UseCors(_defaultCorsPolicyName); // Enable CORS!
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAbpRequestLocalization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<AbpCommonHub>("/signalr");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
});
options.IndexStream = () => Assembly.GetExecutingAssembly()
options.DisplayRequestDuration(); // Controls the display of the request duration (in milliseconds) for "Try it out" requests.
});
// Use Azure App Configuration middleware for dynamic configuration refresh.
app.UseAzureAppConfiguration();
}
}
Custom Controller where I get the null values:
[Route("api/[controller]/[action]")]
public class AzureAppConfigTest : AbpControllerBase
{
public Settings _settings { get; }
public AzureAppConfigTest(IOptionsSnapshot<Settings> options
)
{
_settings = options.Value;
}
[HttpPost]
public string Test()
{
return _settings.Message; // The Problem is here
}
}
I need to get the values else where in the Application, I tried changing IOptionsSnapshot for IOptions but I can't make it work, Iv'e been stuck with this about two week but since I'm new in the Microsoft world I can't see clearly where the problem is, Thanks in Advance
Update:
I am able to use the configuration at the Presentation Layer, but If I try to use it on the Application layer I don't get the values.

Related

System.NullReferenceException on accessing the Base URL from the appSettings.json

I have the Base URL within the appsettings.json like below
"RM": {
"BaseAddress": "https://rm-dev.abc.org/"
},
With in the Class where I am trying to make a call this endpoint
public class InventorySearchLogic
{
private readonly SMContext _context;
private readonly IConfiguration _iconfiguration;
public InventorySearchLogic(SMContext context, IConfiguration iconfiguration)
{
_context = context;
_iconfiguration = iconfiguration;
}
public InventorySearchLogic(SMContext context)
{
}
public async Task<string> GetRoomID(string roomName)
{
//string rmID = "";
using (var client = new HttpClient())
{
RmRoom retRoom = new RmRoom();
client.BaseAddress = new Uri(_iconfiguration.GetSection("RM").GetSection("BaseAddress").Value);
client.DefaultRequestHeaders.Accept.Clear();
When debugging it throws error like System.NullReferenceException: Message=Object reference not set to an instance of an object. how to access the base URL from appsettings.json
I am not sure how to use the ConfigurationBuilder() as I have different apSettings.json file one for each environment like appsettings.Development.json , appsettings.QA.json, appsettings.PROD.json
Below is my Startup
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews();
services.AddSession();
services.AddMemoryCache();
services.AddDbContextPool<SurplusMouseContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("SMConnectionStrings"),
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure();
});
});
services.AddHttpContextAccessor();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
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.UseSession();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Customers}/{action=Index}/{id?}");
});
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
You're already injecting an IConfiguration in your service and saving it as _iconfiguration. Assuming that's not the null value, then simply use .GetValue to retrieve a value.
string baseAddress = _iconfiguration.GetSection("RM").GetValue<string>("BaseAddress");
Read more about ASP.Net configuration
Well, it seems that _iconfiguration is also null.
You've indicated in the comments that you're creating an instance of InventorySearchLogic from a controller, such as
// inside controller logic
var searchLogic = new InventorySearchLogic(_context, _iconfiguration);
This is the wrong approach. Instead, you should register this class as a DI service (although you should also add an interface, it's not necessary right now).
In your Startup's ConfigureServices method, add
services.AddTransient<InventorySearchLogic>();
Then instead of manually creating a variable of type InventorySearchLogic, request it though DI
// your controller constructor
private readonly InventorySearchLogic searchLogic;
public MyController(InventorySearchLogic searchLogic)
{
this.searchLogic = searchLogic;
}
This way, InventorySearchLogic's constructor correctly gets the DI services it's looking for. You will have to move the SMContext context. Maybe move that to the method's parameters?

Subscriptions in GraphQL .NET Core doesn't send response to client

I'm building a GraphQL API in Asp Net Core 3.1. I'm trying to add a subscription that send a new entity to subscriber when it is added.
When I execute the subscription from the /ui/playground the handshake with server seems to be successed:
GraphQL http request websocket:
When I execute the mutation that adds a review it successed and create a record on the db, but the above screen reamins as it is, no updates, no data receveived from the socket.
This is the mutation:
Field<ReviewType>(
"createReview",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<ReviewInput>>
{
Name = "reviewInput"
}
),
resolve: context =>
{
var review = context.GetArgument<Review>("reviewInput");
var rev = reviewService.Add(review);
return rev;
}
);
ShopSubscrition.cs
public partial class ShopSubscription : ObjectGraphType
{
private readonly IReviewService _reviewService;
public ShopSubscription(IReviewService reviewService)
{
_reviewService = reviewService;
AddField(new EventStreamFieldType
{
Name = "reviewAdded",
Type = typeof(ReviewType),
Resolver = new FuncFieldResolver<Review>((context) => context.Source as Review),
Subscriber = new EventStreamResolver<Review>((context) => _reviewService.ReviewAdded())
});
}
}
ReviewService.cs
public class ReviewService : IReviewService
{
private readonly IReviewRepository _reviewRepository;
private readonly ISubject<Review> _sub = new ReplaySubject<Review>(1);
public ReviewService(IReviewRepository reviewRepository)
{
_reviewRepository = reviewRepository;
}
public Review Add(Review review)
{
var addedEntity = _reviewRepository.Add(review);
_sub.OnNext(review);
return review;
}
public IObservable<Review> ReviewAdded()
{
return _sub.AsObservable();
}
}
I post the Startup.cs too, maybe it can helps.
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddDbContext<ShopDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddScoped<ISupplierRepository, SupplierRepository>();
services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<IReviewRepository, ReviewRepository>();
services.AddScoped<IReviewService, ReviewService>();
services.AddSingleton<IDataLoaderContextAccessor, DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();
services.AddScoped<ShopSchema>();
services.AddGraphQL(options =>
{
options.EnableMetrics = false;
})
.AddWebSockets()
.AddSystemTextJson()
.AddGraphTypes(typeof(ShopSchema), ServiceLifetime.Scoped).AddDataLoader();
services.AddControllers()
.AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ShopDbContext dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("Cors");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseWebSockets();
app.UseGraphQLWebSockets<ShopSchema>("/graphql");
app.UseGraphQL<ShopSchema>();
app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions { GraphQLEndPoint ="/graphql", SchemaPollingEnabled = false });
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
dbContext.SeedData();
}
}
Thanks in advance for help.
After a deeper investigation I found out the problem. I post the solution, maybe could help someone.
The problem was about Dependency Injection: the class containing the subscription "notification logic" (in my case ReviewService.cs) must be registered as Singleton instead of Scoped. This caused a sort of chain reaction that bring the repositories classes to be registered as Transient.
This is the working code:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("Cors",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddDbContext<ShopDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddTransient<ISupplierRepository, SupplierRepository>();
services.AddTransient<IProductRepository, ProductRepository>();
services.AddTransient<IReviewRepository, ReviewRepository>();
services.AddSingleton<IReviewService, ReviewService>();
services.AddSingleton<IDataLoaderContextAccessor, DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();
services.AddScoped<ShopSchema>();
services.AddGraphQL(options =>
{
options.EnableMetrics = false; // info sulla richiesta (ms, campi richiesti, ecc)
})
.AddWebSockets()
.AddSystemTextJson()
.AddGraphTypes(typeof(ShopSchema), ServiceLifetime.Scoped).AddDataLoader();
services.AddControllers()
.AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}

After clone of ASP.NET Core Web API project on other computer receiving MediatR error

In my computer application works fine, but other computers receiving next error after trying handle any request:
Error constructing handler for request of type MediatR.IRequestHandler`2[Application.User.Register+Command,Application.User.User]. Register your handlers with the container. See the samples in GitHub for examples
connection string
I register MediatR with following line in my Startup.cs:
services.AddMediatR(typeof(List.Handler).Assembly);
My Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(opt =>
{
opt.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddCors(opt =>
{
opt.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000");
});
});
services.AddMvc(opt =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
opt.Filters.Add(new AuthorizeFilter(policy));
})
.AddFluentValidation(cfg => cfg.RegisterValidatorsFromAssemblyContaining<Create>())
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var builder = services.AddIdentityCore<AppUser>();
var identityBuilder = new IdentityBuilder(builder.UserType, builder.Services);
identityBuilder.AddEntityFrameworkStores<DataContext>();
identityBuilder.AddSignInManager<SignInManager<AppUser>>();
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateAudience = false,
ValidateIssuer = false
};
});
services.AddScoped<IJwtGenerator, JwtGenerator>();
services.AddScoped<IUserAccessor, UserAccessor>();
services.AddMediatR(typeof(List.Handler).Assembly);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<ErrorHandlingMiddleware>();
if (env.IsDevelopment())
{
//app.UseDeveloperExceptionPage();
}
else
{
// app.UseHsts();
}
// app.UseHttpsRedirection();
app.UseAuthentication();
app.UseCors("CorsPolicy");
app.UseMvc();
}
}
Problem is that i cannot reproduce same issue on my computer.
Problem was on another level:
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
It was problem with reading Configuration. After fixing it, all works as designed.

asp.net core 2.1 cross orgin policy. Only single url working when added as CORS

I am trying to add multiple rul which should be whitelisted for CORS.
Problem is only single url work. My code is as following
public class StartupShutdownHandler
{
private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private const string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public StartupShutdownHandler(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; }).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters();
CorsRelatedPolicyAddition(services);
}
private void CorsRelatedPolicyAddition(IServiceCollection services)
{
/* var lstofCors = ConfigurationHandler.GetSection<List<string>>(StringConstants.AppSettingsKeys.CORSWhitelistedURL);
*/
var lstofCors = new List<string> {"url1", "url2"}
if (lstofCors != null && lstofCors.Count > 0 && lstofCors.Any(h => !string.IsNullOrWhiteSpace(h)))
{
services.AddCors(options =>
{
//https://stackoverflow.com/questions/43985620/asp-net-core-use-multiple-cors-policies
foreach (var entry in lstofCors.FindAll(h => !string.IsNullOrWhiteSpace(h)))
{
options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins(entry); });
}
});
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(MyAllowSpecificOrigins);
// CheckAndEnableDetailLogs(app);
app.UseMvc();
}
}
You are overriding the options for every entry in your array.
Just add the entries as an array of strings.
var lstofCors = new string[] {"url1", "url2"};
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins(lstofCors.ToArray()).AllowAnyMethod(); });
});
}
Edit:
I have added AllowAnyMethod() as looks like only get method is working

How to implement authorization using GraphQL.NET at Resolver function level?

I am looking for sample code and examples regarding how to implement authorization at resolver function level using GraphQL.NET and ASP.NET CORE 2.
Basically I am trying to prevent the execution of query if the request is not authorized.
Can anyone help me to get some good tutorials or code samples as reference for the implementation.
For graphql-dotnet/authorization, the page for AspNetCore has not been released, refer Add GraphQL.Server.Authorization.AspNetCore NuGet package #171.
You could implement Authorization.AspNetCore for your own use.
After implement Authorization.AspNetCore, you could configure the Authorize like:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
{
Configuration = configuration;
Environment = hostingEnvironment;
}
public IConfiguration Configuration { get; }
public IHostingEnvironment Environment { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
services.AddGraphQL(options =>
{
options.EnableMetrics = true;
options.ExposeExceptions = Environment.IsDevelopment();
//options.
})
.AddGraphQLAuthorization(options =>
{
options.AddPolicy("Authorized", p => p.RequireAuthenticatedUser());
//var policy = new AuthorizationPolicyBuilder()
// .
//options.AddPolicy("Authorized", p => p.RequireClaim(ClaimTypes.Name, "Tom"));
});
//.AddUserContextBuilder(context => new GraphQLUserContext { User = context.User });
services.AddSingleton<MessageSchema>();
services.AddSingleton<MessageQuery>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseGraphQL<MessageSchema>("/graphql");
app.UseGraphQLPlayground(new GraphQLPlaygroundOptions()
{
Path = "/ui/playground"
});
app.UseGraphiQLServer(new GraphiQLOptions
{
GraphiQLPath = "/ui/graphiql",
GraphQLEndPoint = "/graphql"
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Schema
public class MessageQuery : ObjectGraphType<Message>
{
public MessageQuery()
{
Field(o => o.Content).Resolve(o => "This is Content").AuthorizeWith("Authorized");
Field(o => o.SentAt);
Field(o => o.Sub).Resolve(o => "This is Sub");
}
}
For complete demo, refer GraphQLNet.
To get GraphQL.Net's authorization to work in ASP.NET Core, first install this package:
GraphQL.Server.Authorization.AspNetCore
In Startup.cs add the following in ConfigureServices. Make sure to add these using statements:
using GraphQL.Validation;
using GraphQL.Server.Authorization.AspNetCore;
public void ConfigureServices(IServiceCollection services)
{
//... other code
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services
.AddTransient<IValidationRule, AuthorizationValidationRule>()
.AddAuthorization(options =>
{
options.AddPolicy("LoggedIn", p => p.RequireAuthenticatedUser());
});
//... other code
}
Now you'll be able to use AuthorizeWith() at the resolver level to protect the field. Example:
public class MyQuery : ObjectGraphType
{
public MyQuery(ProductRepository productRepository)
{
Field<ListGraphType<ProductType>>(
"products",
resolve: context => productRepository.GetAllAsync()
).AuthorizeWith("LoggedIn");
}
}
You can also protect all queries by adding this.AuthorizeWith() to the top of the Query constructor like this:
public class MyQuery : ObjectGraphType
{
public MyQuery(ProductRepository productRepository)
{
this.AuthorizeWith("LoggedIn");
Field<ListGraphType<ProductType>>(
"products",
resolve: context => productRepository.GetAllAsync()
);
}
}
With that, any unauthenticated access to your GraphQL endpoint will be rejected.
Now in terms of logging someone in, there are many ways to do that. Here's a quick Cookie based authentication example:
Configure cookie based authentication in Startup.cs' ConfigureServices:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(o =>
{
o.Cookie.Name = "graph-auth";
});
Use mutation to log someone in:
public class Session
{
public bool IsLoggedIn { get; set; }
}
public class SessionType : ObjectGraphType<Session>
{
public SessionType()
{
Field(t => t.IsLoggedIn);
}
}
public class MyMutation : ObjectGraphType
{
public MyMutation(IHttpContextAccessor contextAccessor)
{
FieldAsync<SessionType>(
"sessions",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "password" }),
resolve: async context =>
{
string password = context.GetArgument<string>("password");
// NEVER DO THIS...for illustration purpose only! Use a proper credential management system instead. :-)
if (password != "123")
return new Session { IsLoggedIn = false };
var principal = new ClaimsPrincipal(new ClaimsIdentity("Cookie"));
await contextAccessor.HttpContext.SignInAsync(principal, new AuthenticationProperties
{
ExpiresUtc = DateTime.UtcNow.AddMonths(6),
IsPersistent = true
});
return new Session { IsLoggedIn = true };
});
}
}

Categories

Resources