You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
OpenIddict and TokenValidation in an OC module (Feature): how to configure it? And why the ContentManager always return a null Author and Owner?
#16950
We have partially discussed this topic here, but now that we have identified the problem in the authentication procedure, we want to open this new thread as the previous one has become too large.
In short, we are experiencing an issue with the Token Validation inside our Orchard Core 1.8.2 module (Feature). We are working on developing a Chat microservice, and we have an OC module (Feature) utilizing SignalR where we are attempting to implement "Token Validation". Our JWT token is provided by our SSO microservice, which is built using OpenIddict and Orchard Core 1.8.2.
Something is going wrong because whenever we try to create our Content Items using the ContentManager, we always get a null Author and a null Owner. Below you can see a screenshot. Instead, running the Chat microservice in localhost, if no one log into the backoffice, the ContentManager fail to instantiate a new content item with the error: System.ArgumentNullException: 'Value cannot be null. Arg_ParamName_Name'. This happens at this line of the OC code, because contentTypeDefinition is null, even though the content type exists.
Screenshot of ContentManager, where Author and Owner are null:
We suspect there’s an issue with our JWT configuration or in the Startup.cs of our OC module.
Could it be that the Audience is set incorrectly? In the generated JWT, we are seeing oct:Default (we have only one tenant), or could it be something else? We're at our wit's end trying to solve this 🫤
Maybe @kevinchalet, since you are the creator of OpenIddict ☺️, you have an easy answer for us?
Thank you so much!
Here some of our code we mentioned above
Here the Startup.cs:
using Bookstore.Module.SignalR.OurHub;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.IdentityModel.Tokens;namespace Bookstore.Module.SignalR
{publicclassStartup:StartupBase{publicoverridevoidConfigureServices(IServiceCollectionservices){
services.AddAuthentication().AddJwtBearer("ChatHub",options =>{// Configure validation Authority options.Authority ="http://host.docker.internal:12103/";// URL OpenIddict server options.Audience ="oct:Default";// Orchard Core Tenant Default audience (as shown in the JWT token) options.RequireHttpsMetadata =false;// TODO: Remove for production// Configure token validation options.TokenValidationParameters =new TokenValidationParameters{ValidateIssuer=true,ValidateAudience=true,ValidateLifetime=true};});// Register SignalR services in Orchard Core
services.AddSignalR();}publicoverridevoidConfigure(IApplicationBuilderapp){// Use endpoint routing to map the SignalR hubs
app.UseEndpoints(endpoints =>{// Map the SignalR hub for chat endpoints.MapHub<ChatHub>("/chathub");});}}}
Here the ChatHub.cs (this class is inside our OC module, the IChatHandler instead is in the Chat Microservice). On top of this class there's our custom "ChatHub" API attribute: [Authorize(AuthenticationSchemes = "ChatHub"), IgnoreAntiforgeryToken]:
using Microsoft.AspNetCore.SignalR;using Bookstore.Common.Abstractions;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Logging;using Bookstore.Common.Models.Api.Microservices.Chat;using System.Net;using Bookstore.Common.Models;namespace Bookstore.Module.SignalR.OurHub
{[Authorize(AuthenticationSchemes ="ChatHub"),IgnoreAntiforgeryToken]publicclassChatHub:Hub{privatereadonlyIChatHandler_chatHandler;privatereadonlyILogger<ChatHub>_logger;publicChatHub(IChatHandlerchatHandler,ILogger<ChatHub>logger){_chatHandler=chatHandler;_logger=logger;}// This method is the ONLY ONE called by the client after the first connection, where is also called OnConnectedAsync()publicasync Task SendMessageToRoom(stringroomName,stringuserAId,stringuserAName,stringuserBId,stringuserBName,stringmessage){
_logger.LogInformation($"{nameof(ChatHub)}-{nameof(SendMessageToRoom)} started for room: {roomName}");// Step 1: Check if the chat room existsApiResult<List<ChatMessageApiModel>>roomResult=await _chatHandler.GetMessagesForRoomAsync(roomName, userAId, userBId);if(roomResult.StatusCode == HttpStatusCode.NotFound){
_logger.LogWarning($"Room {roomName} does not exist. Creating a new chat room.");// Create a new chat room if it doesn't existvarnewChatRoomApiModel=new ChatRoomApiModel
{RoomName=roomName,UserAId=userAId,UserAName=userAName,UserBId=userBId,UserBName=userBName,};varcreateRoomResult=await _chatHandler.CreateChatRoomAsync(newChatRoomApiModel);if(createRoomResult.StatusCode != HttpStatusCode.OK){
_logger.LogError($"Failed to create room {roomName}.");await Clients.Caller.SendAsync("ErrorMessage","Failed to create chat room.");return;}
_logger.LogInformation($"Room {roomName} successfully created.");}// Step 2: Create a ChatMessageApiModel object with message detailsvarchatMessageApiModel=new ChatMessageApiModel
{UserName=userAName,// Name of the user sending the messageMessage=message};// Step 3: Save the message using the ChatHandlervarsaveMessageResult=await _chatHandler.SaveMessageAsync(roomName, userAId, userAName, userBId, userBName, chatMessageApiModel);// Step 4: Check if the message was successfully savedif(saveMessageResult.StatusCode == HttpStatusCode.OK){// Send the message to all clients in the group (room)await Clients.Group(roomName).SendAsync("ReceiveMessage", userAName, message);}else{// Handle errors, such as logging or notifying the clientawait Clients.Caller.SendAsync("ErrorMessage","Failed to send the message.");}}publicoverrideasync Task OnConnectedAsync(){varroomName= Context.GetHttpContext().Request.Query["room"];varuserAId= Context.GetHttpContext().Request.Query["userAId"];varuserBId= Context.GetHttpContext().Request.Query["userBId"];varuserAName= Context.GetHttpContext().Request.Query["userAName"];varuserBName= Context.GetHttpContext().Request.Query["userBName"];if(string.IsNullOrWhiteSpace(roomName)||string.IsNullOrWhiteSpace(userAId)||string.IsNullOrWhiteSpace(userBId)||string.IsNullOrWhiteSpace(userAName)||string.IsNullOrWhiteSpace(userBName)){stringerrorMessage=$"Missing required parameters. Room: {roomName}, userAId: {userAId}, userBId: {userBId}, userAName: {userAName}, userBName: {userBName}.";
_logger.LogError(errorMessage);await Clients.Caller.SendAsync("ErrorMessage", errorMessage);return;}// Check if userAId and userBId are the sameif(userAId==userBId){stringerrorMessage=$"userAId: \"{userAId}\" and userBId: \"{userBId}\" cannot be the same!";
_logger.LogError(errorMessage);await Clients.Caller.SendAsync("ErrorMessage", errorMessage);return;}
_logger.LogInformation($"User connected to room {roomName}, UserAId: {userAId}, UserBId: {userBId}.");// Step 1: Add the user to the room groupawait Groups.AddToGroupAsync(Context.ConnectionId, roomName);// Step 2: Check if the chat room exists; if not, create a new oneApiResult<List<ChatMessageApiModel>>roomResult=await _chatHandler.GetMessagesForRoomAsync(roomName, userAId, userBId);if(roomResult.StatusCode == HttpStatusCode.NotFound){
_logger.LogWarning($"Room {roomName} does not exist. Creating a new chat room.");varnewChatRoomApiModel=new ChatRoomApiModel
{RoomName=roomName,UserAId=userAId,UserAName=userAName,UserBId=userBId,UserBName=userBName,};varcreateRoomResult=await _chatHandler.CreateChatRoomAsync(newChatRoomApiModel);if(createRoomResult.StatusCode != HttpStatusCode.OK){
_logger.LogError($"Failed to create room {roomName}.");await Clients.Caller.SendAsync("ErrorMessage","Failed to create chat room.");return;}
_logger.LogInformation($"Room {roomName} successfully created.");}else{// Step 3: If room exists, send previous messages to the clientforeach(var message in roomResult.Data){await Clients.Caller.SendAsync("ReceiveMessage", message.UserName, message.Message);}}awaitbase.OnConnectedAsync();}}}
Our JWT token decoded, released by our OpenIddict SSO:
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Hi everyone,
We have partially discussed this topic here, but now that we have identified the problem in the authentication procedure, we want to open this new thread as the previous one has become too large.
In short, we are experiencing an issue with the
Token Validation
inside our Orchard Core 1.8.2 module (Feature). We are working on developing a Chat microservice, and we have an OC module (Feature) utilizing SignalR where we are attempting to implement "Token Validation". Our JWT token is provided by our SSO microservice, which is built using OpenIddict and Orchard Core 1.8.2.Something is going wrong because whenever we try to create our Content Items using the
ContentManager
, we always get a nullAuthor
and a nullOwner
. Below you can see a screenshot.Instead, running the Chat microservice in localhost, if no one log into the backoffice, the ContentManager fail to instantiate a new content item with the error:
System.ArgumentNullException: 'Value cannot be null. Arg_ParamName_Name'
. This happens at this line of the OC code, becausecontentTypeDefinition
is null, even though the content type exists.Screenshot of
ContentManager
, whereAuthor
andOwner
are null:We suspect there’s an issue with our JWT configuration or in the Startup.cs of our OC module.
Audience
is set incorrectly? In the generated JWT, we are seeingoct:Default
(we have only one tenant), or could it be something else? We're at our wit's end trying to solve this 🫤Maybe @kevinchalet, since you are the creator of OpenIddict☺️ , you have an easy answer for us?
Thank you so much!
Here some of our code we mentioned above
Here the
Startup.cs
:Here the
ChatHub.cs
(this class is inside our OC module, theIChatHandler
instead is in the Chat Microservice). On top of this class there's our custom "ChatHub" API attribute:[Authorize(AuthenticationSchemes = "ChatHub"), IgnoreAntiforgeryToken]
:Our
JWT token decoded
, released by our OpenIddict SSO:Beta Was this translation helpful? Give feedback.
All reactions