I have managed to get Identity Server 4 up to the point where I need to grant the app my consent so to speak but the consent page wont show. This is what I get
This localhost page can’t be found No webpage was found for the web address: https://localhost:44361/consent?returnUrl=%2Fconnect%2Fauthorize%2Fconsent%3Fresponse_type%3Did_token%2520token%26client_id%3Dangular2client%26redirect_uri%3Dhttps%253A%252F%252Flocalhost%253A44380%26scope%3Dopenid%2520email%2520profile%2520securedfilesscope%2520resourcescope%26nonce%3DN0.46395672677896951497118418043%26state%3D14971184180430.1487668170892953
Below is he Consent Controller with the index method that is suppose to called to return the consent view or page. It appears like the controller is not being hit at all let alone call the index method
[Route("api/[controller]")]
public class ConsentController : Controller
{
// GET: api/values
private readonly ILogger<ConsentController> _logger;
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
private readonly IIdentityServerInteractionService _interaction;
public ConsentController(
ILogger<ConsentController> logger,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IResourceStore resourceStore)
{
_logger = logger;
_interaction = interaction;
_clientStore = clientStore;
_resourceStore = resourceStore;
}
/// <summary>
/// Shows the consent screen
/// </summary>
/// <param name="returnUrl"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Index(string returnUrl)
{
var vm = await BuildViewModelAsync(returnUrl);
if (vm != null)
{
return View("Index", vm);
}
return View("Error");
}
}
Not sure why it worked but this is what happened. I removed this [Route("api/[controller]")] from the Consent Controller and the consents page showed up
Related
So, I have a bit of an annoying issue. It seems that when using the ASP.NET Core 6 ReactJS template, I can log in, log out, register accounts etc, and the ReactJS menu shows the active username, but am having issues reaching the active user in a controller.
Also, Authorize does not work for controllers (no scope or specific claim defined) as it always returns Unauthorized.
I have tried injecting the HTTPContextAccessor, SigninManager, Usermanager in a controller like so;
[Authorize]
[ApiController]
[Route("/api/[controller]")]
public class MyController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<MyController> _logger;
private readonly ApplicationDbContext _applicationDbContext;
public MyController(
ILogger<MyController> logger,
ApplicationDbContext applicationDbContext,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IHttpContextAccessor httpContextAccessor)
{
_applicationDbContext = applicationDbContext;
_logger = logger;
_userManager = userManager;
_signInManager = signInManager;
_httpContextAccessor = httpContextAccessor;
}
And using it in the controller method like so, where ALL testX variations return null on the user identity, rendering me unable to retrieve the active username and/or Id. Test4 generates an error as it cannot return .Value of null.
[HttpGet]
public IEnumerable<Something> Get()
{
var test1 = User.Identity!.Name!;
var test2 = HttpContext.Request;
var test3 = await _userManager.GetUserAsync(User);
var test4 = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
var test5 = _applicationDbContext.Users.Find(test4);
var test6 = user.UserName;
return Something;
}
into the controller and loading it in Program.cs like so
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Any takers? Note, this is just using the base template without adding complexity, functionality etc...
Thanks in advance for your help!
I only seem to be able to handle EventAggregator events from the ShellViewModel, but I want to handle it from LoginViewModel.
The ShellViewModel constructs LoginViewModel as it's Active Item. I've also set it up to inherit from IHandle<AuthenticatedMessage> as a test that event publishing is working. It is able to handle that event. I haven't shown any Unsubscribe events in my code for brevity.
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<AuthenticatedMessage>
{
public ShellViewModel(IEventAggregator eventAggregator, LoginViewModel loginViewModel)
{
_eventAggregator = eventAggregator;
_loginViewModel = loginViewModel;
}
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
_eventAggregator.SubscribeOnPublishedThread(this);
await ActivateItemAsync(_loginViewModel);
}
public async Task HandleAsync(AuthenticatedMessage authCode, CancellationToken cancellationToken)
{
// this is reached! So the event is publishing successfully.
await Task.CompletedTask;
}
}
LoginViewModel also subscribes to this event, but it's Handle method is not invoked.
The Login method is responsible for creating the LoginWindowViewModel Window (shown underneath) which publishes the event.
public class LoginViewModel : Screen, IHandle<AuthenticatedMessage>
{
private IEventAggregator _eventAggregator;
private readonly IWindowManager _windowManager;
private readonly ILoginWindowViewModelFactory _LoginWindowViewModelFactory;
public LoginViewModel(IEventAggregator eventAggregator,
IWindowManager windowManager,
ILoginWindowViewModelFactory loginWindowViewModelFactory)
{
_eventAggregator = eventAggregator;
_windowManager = windowManager;
_LoginWindowViewModelFactory = loginWindowViewModelFactory;
}
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
_eventAggregator.SubscribeOnPublishedThread(this);
}
// This is bound to a button click event. It creates a window.
public async void Login()
{
Uri loginUri = new Uri(_api.BaseLoginUrl);
await _windowManager.ShowWindowAsync(
_ndLoginWindowViewModelFactory.Create(loginUri, _eventAggregator));
}
public async Task HandleAsync(AuthenticatedMessage authCode, CancellationToken cancellationToken)
{
// why is this is never reached?
await Task.CompletedTask;
}
}
The LoginWindowViewModel that publishes a AuthenticatedMessage event:
public class LoginWindowViewModel : Screen
{
private readonly IEventAggregator _eventAggregator;
private readonly Uri _initialUri;
public NDLoginWindowViewModel(Uri initialUri, IEventAggregator eventAggregator)
{
_initialUri = initialUri;
_eventAggregator = eventAggregator;
}
// bound to the WebView2 (browser control) event
public async void NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
string authCode = HttpUtility.ParseQueryString(new Uri(e.Uri).Query).Get("code");
// Publish event here. LoginViewModel should handle this, but currently only ShellViewModel can.
await _eventAggregator.PublishOnUIThreadAsync(new AuthenticatedMessage(authCode));
}
}
}
I resolved the issue after moving eventAggregator.SubscribeOnPublishedThread(this); to the LoginViewModel constructor, instead of the OnActivateAsync() method.
From here:
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
_eventAggregator.SubscribeOnPublishedThread(this);
}
To here:
public LoginViewModel(IEventAggregator eventAggregator,
IWindowManager windowManager,
ILoginWindowViewModelFactory loginWindowViewModelFactory)
{
_eventAggregator = eventAggregator;
_windowManager = windowManager;
_LoginWindowViewModelFactory = loginWindowViewModelFactory;
_eventAggregator.SubscribeOnPublishedThread(this);
}
EDIT:
The OnActivateAsync method isn't being called when the View is first created in the ShellViewModel because it is my root Screen and Conductor. So the Subscription was never taking place.
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
{
...
protected override async Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken);
await ActivateItemAsync(_loginViewModel);
// IsActive = false here, therefore the child Screen `_loginViewModel`
// is also not active. Result is that OnActivateAsync
// in this view model does not get called.
}
}
It is directly related to this problem and answer.
That explains why moving it to the constructor solved the problem.
The final solution was to add _eventAggregator.SubscribeOnPublishedThread(this); in both the Constructor AND OnActivateAsync method. This allows me to resubscribe to the event after I navigate away from this viewmodel and come back to it.
I have a standard Hoemcontroller in ASP.NET Core MVC:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index(string user)
{
if(user != null)
{
TempData["UserName"] = user;
return View("Index", user);
}
return View("Index");
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
In the Index Action there will be a parameter sent from a winforms application. The string will contain the username of the client connecting to the website. This is the code for winforms:
public partial class Form1 : Form
{
public ChromiumWebBrowser chromeBrowser;
public Form1()
{
InitializeComponent();
InitializeChromium();
this.WindowState = FormWindowState.Maximized;
}
public void InitializeChromium()
{
CefSettings settings = new CefSettings();
Cef.Initialize(settings);
Cef.EnableHighDPISupport();
chromeBrowser = new ChromiumWebBrowser("https://localhost:5001/Home/Index/" + Environment.UserName);
this.Controls.Add(chromeBrowser);
//chromeBrowser.Dock = DockStyle.Fill;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Cef.Shutdown();
}
}
Now I am unsure on how to handle this on the webserver. I get the username inside the HomeController but in the same time when a user goes to the other pages with their controllers then the user should see only his content. Is that even possible?
It is not good practice to do authorization through a parameter in URI. For that, you should use Authentication (when the user passes his login and password) and receive a token with permissions. After that, you pass the token to the server and check permission there(using Authorize attribute for example). Example
If you are making a test project, and you don't need authentication at all, then you can pass a username everywhere you need and write some code to handle the content of every user (using headers, URI parameters, etc.)
I have a WPF windows application that uses the ms ribbon control for the menu. In my infrastructure project I want to have a shared service that will be referenced in all modules. Each module will then use that service to define what menu items should be displayed for the module.
I read this Prism+MEF: delayed a service export from prism-module but can't get my other modules to recognize the service.
The service
namespace Infrastructure
{
[ModuleExport("InfModule", typeof(InfModule), InitializationMode = InitializationMode.WhenAvailable)]
[PartCreationPolicy(CreationPolicy.Shared)]
public class InfModule : IModule
{
[Export(typeof(IMenuService))]
public IMenuService MenuService { get; private set; }
public void Initialize()
{
MenuService = new MenuService();
MenuService.AddItem("test");
}
}
}
The module
namespace Classic
{
[ModuleExport("Classic", typeof(Classic), InitializationMode = InitializationMode.WhenAvailable)]
[ModuleDependency("InfModule")]
public class Classic : IModule
{
private IRegionManager _regionManager;
[Import(typeof(IMenuService))]
private IMenuService menuService { get; set; }
[ImportingConstructor]
public Classic(IRegionManager regionManager)
{
this._regionManager = regionManager;
// This shows as true
Debug.WriteLine(menuService == null);
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion("RibbonRegion", typeof(Views.RibbonTabMenu));
// This shows as true
Debug.WriteLine(menuService == null);
}
}
}
I would have expected one of the debug lines to output as false since its imported. Any idea's what I'm missing?
Property imports will never be set while running the constructor, since you can't set properties on an object until it's constructed.
The other problem is that in InfModule, you are setting the exported value too late. MEF only looks at the value for an export once, after that it caches the value and doesn't call the getter again. In this case it is getting the export before Initialize() is called. The logic to set the export needs to either run from the constructor or from code in the property getter.
I use Caliburn.Micto as MVVM framework for my WPF application and also MEF for injection.
UML of my application look like this: http://i54.tinypic.com/2n1b4mx.png
My scenario is: I create in view-model-1 (in project is LogOnViewModel) new view-model-2 (in my project is MessengerViewModel) with shell-view-model method.
I need pass object from view-model-1 to constructor of view-model-2.
I use MEF on injection class from external assembly which is loaded in boostraper class.
On creation of new view-models I use abstract factory pattern, here is my implementation:
/// <summary>
/// Factory interfaces
/// </summary>
public interface IViewModelFactory
{
ILogOnViewModel CreateLogOnViewModel(IShellViewModel shellViewModel);
IMessengerViewModel CreateMessengerViewModel(IShellViewModel shellViewModel, PokecAccount account);
}
/// <summary>
/// Concrent implementation of factory
/// </summary>
[Export(typeof(IViewModelFactory))]
public class DefaulFactoryViewModel:IViewModelFactory
{
#region Implementation of IViewModelFactory
//create start up view-model
public ILogOnViewModel CreateLogOnViewModel(IShellViewModel shellViewModel)
{
return new LogOnViewModel(shellViewModel);
}
//this method create new view model
//it is used in LogOnViewModel
public IMessengerViewModel CreateMessengerViewModel(IShellViewModel shellViewModel, PokecAccount account)
{
return new MessengerViewModel(shellViewModel, account);
}
}
I use this factory class in my shell-view-model. Shell-view-model class look like this:
/// <summary>
/// Shell model interface
/// </summary>
public interface IShellViewModel
{
//create start up view-model
void ShowLogOnView();
//this method create new view model
//it is used in LogOnViewModel
void ShowMessengerView(PokecAccount account);
}
[Export(typeof(IShellViewModel))]
public class ShellViewModel : Conductor<IScreen>, IShellViewModel
{
//factory interface
private readonly IViewModelFactory _factory;
[ImportingConstructor]
public ShellViewModel(IViewModelFactory factory)
{
//inject factory
_factory = factory;
//show startup view model
ShowLogOnView();
}
public void ShowLogOnView()
{
//create LogOnViewModel class with factory
var model = _factory.CreateLogOnViewModel(this);
ActivateItem(model);
}
/// <summary>
/// Create MessengerViewModel
/// </summary>
/// <param name="account">account in this case is send from LogOnViewModel class </param>
public void ShowMessengerView(PokecAccount account)
{
//create MessengerViewModel class with factory
var model = _factory.CreateMessengerViewModel(this, account);
ActivateItem(model);
}
}
}
Start up view-model. LogOnViewModel class:
public interface ILogOnViewModel : IScreen, IDataErrorInfo
{
string Nick { get; set; }
string Password { get; set; }
bool CanLogOn { get; set; }
void LogOn(string nick, string password);
}
public class LogOnViewModel : Screen, ILogOnViewModel
{
/// <summary>
/// inject class from external assembly
/// after creation of this class is still null
/// </summary>
[Import]
public IPokecConnection PokecConn { get; set; }
private readonly IShellViewModel _shellViewModel = null;
private PokecAccount _account = null;
public LogOnViewModel(IShellViewModel shellViewModel)
{
_shellViewModel = shellViewModel;
_account = new PokecAccount();
}
//CREATE NEW VIEW MODEL
public void CreateNewView()
{
//create new view-model (MessengerViewModel)
_shellViewModel.ShowMessengerView(_account);
}
}
MessengerViewModel class:
public interface IMessengerViewModel : IScreen
{
BitmapImage AvatarImage { get; set; }
string AvatarStatus { get; set; }
KeyValuePair<string, Friend> SelectedFriend { get; set; }
}
public class MessengerViewModel : Screen, IMessengerViewModel
{
[Import]
private IPokecService _pokecService;
[Import]
private IPokecConnection _pokecConn;
private IShellViewModel _shellViewModel = null;
private PokecAccount _account = null;
public MessengerViewModel(IShellViewModel shellViewModel, PokecAccount account)
{
_shellViewModel = shellViewModel;
_account = account;
}
}
I have problem with injection into view-model class. On creation of view-model classes I use factory pattern, but I need inject in this class also from external assembly.
For example: After creation of LogOnVieModel class is IPokecConnection PokecConn{ get; set;} still null.
What is the most suitable solution in my case? Where is it problem ? Thank for help.
The factory pattern you are using doesn't do any composition outside of composing the ViewScreenModel class itself. You need to tell MEF to compose your view models, if they are not being created through injection. Update your factory class to compose the instance before returning it;
public ILogOnViewModel CreateLogOnViewModel
{
var model = new LogOnViewModel();
var container = // set this to your reference of CompositionContainer
container.ComposeParts(model);
return model;
}
...where Bootstapper.Container is your instance of CompositionContainer.
On another note, why have you made another account, instead of using your current one