Dependency Injection Using IdentityUser

lesponce 176 Reputation points
2022-03-08T14:49:17.71+00:00

I got a razor page, I got the following code that I'd like to translate to C# code.

@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

How do I translate to C# code? Should I have it coded in the startup class and set it up like a service? If so, how do I code this?

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,178 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,266 questions
0 comments No comments
{count} votes

5 answers

Sort by: Most helpful
  1. Michael Taylor 48,486 Reputation points
    2022-03-08T15:12:26.077+00:00

    What do you mean by "translate to C# code"? If you're using Razor Pages then those instances will be passed to your page automatically.

    If you need to register those types then you won't be doing it directly in most cases. If you're using Identity then you would have added the identity middleware to your app during startup. That code would register the types. Something like this, depending upon your provider.

       services.AddDefaultIdentity<IdentityUser>(options => {  
       });  
    

    This is covered here.

    0 comments No comments

  2. Bruce (SqlWork.com) 56,526 Reputation points
    2022-03-08T16:59:19.957+00:00

    DI is done via the class constructor. the c# would be:

    public MyClass 
    { 
         private SignInManager<IdentityUser> SignInManager; 
         private UserManager<IdentityUser> UserManager; 
    
         public MyClass(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager) 
         { 
               this.SignInManager = signInManager; 
               this.UserManager = userManager; 
         } 
    } 
    

    in razor pages, you don't define the constructor, so the @inject directive is used instead. the razor code generator will create the constructor and private variables.

    0 comments No comments

  3. lesponce 176 Reputation points
    2022-03-08T22:50:39.733+00:00

    Thanks for your responses. It's giving me an idea. I'm trying to use a controller that has these entry parms in the constructor:

    UserManager<IdentityUser> userManager,
    SignInManager<IdentityUser> signInManager,
    IConfiguration configuration

    I tried to use @Bruce (SqlWork.com) 's recommendation, but the values are null.

    How do I get userManager and signInManager populated so I can call a method that resides in a Controller?


  4. lesponce 176 Reputation points
    2022-03-09T21:19:28.29+00:00

    Thanks @Michael Taylor

    The app should display a third party page that is related to single sign on. So the controller should trigger that third party page. After the authentication happens I will need to handle the response, but for now.....in order to complete the fist step to get that page displayed, I need to be able to make a code reference that will trigger the controller.

    A working example is calling the controller that I need from a razor page. In my case, I don't want the razor page. Please see code example below. I will list the following:

    1. Index.cshtml file that I don't want, but it's working from the example.
    2. The controller that I need.
    3. The startup class. @Anonymous @默 IndexModel @{ ViewData["Title"] = "Home"; } @using Microsoft.AspNetCore.Identity @inject SignInManager<IdentityUser> SignInManager @inject UserManager<IdentityUser> UserManager <div class="jumbotron"> <h1 class="display-4">Example Service Provider</h1> <p class="lead"> This example demonstrates using the ComponentSpace SAML v2.0 library to enable SAML single sign-on as the service provider. </p> @if (!SignInManager.IsSignedIn(User)) { <p><a asp-area="" asp-controller="Saml" asp-action="InitiateSingleSignOn" class="btn btn-primary btn-lg">SSO to the Identity Provider</a></p> } </div>

    // CONTROLLER:

    using ComponentSpace.Saml2; using ComponentSpace.Saml2.Metadata.Export; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; using System.Xml;

    namespace ExampleServiceProvider.Controllers { [Route("[controller]/[action]")] public class SamlController : Controller { private readonly UserManager<IdentityUser> _userManager; private readonly SignInManager<IdentityUser> _signInManager; private readonly ISamlServiceProvider _samlServiceProvider; private readonly IConfigurationToMetadata _configurationToMetadata; private readonly IConfiguration _configuration;

        public SamlController(
            UserManager&lt;IdentityUser&gt; userManager,
            SignInManager&lt;IdentityUser&gt; signInManager,
            ISamlServiceProvider samlServiceProvider,
            IConfigurationToMetadata configurationToMetadata,
            IConfiguration configuration)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _samlServiceProvider = samlServiceProvider;
            _configurationToMetadata = configurationToMetadata;
            _configuration = configuration;
        }
    
        public async Task&lt;IActionResult&gt; InitiateSingleSignOn(string returnUrl = null)
        {
            var partnerName = _configuration[&#34;PartnerName&#34;];
    
            // To login automatically at the service provider, 
            // initiate single sign-on to the identity provider (SP-initiated SSO).            
            // The return URL is remembered as SAML relay state.
            await _samlServiceProvider.InitiateSsoAsync(partnerName, returnUrl);
    
            return new EmptyResult();
        }
    
        public async Task&lt;IActionResult&gt; InitiateSingleLogout(string returnUrl = null)
        {
            // Request logout at the identity provider.
            await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
    
            return new EmptyResult();
        }
    
        public async Task&lt;IActionResult&gt; AssertionConsumerService()
        {
            // Receive and process the SAML assertion contained in the SAML response.
            // The SAML response is received either as part of IdP-initiated or SP-initiated SSO.
            var ssoResult = await _samlServiceProvider.ReceiveSsoAsync();
    
            // Automatically provision the user.
            // If the user doesn&#39;t exist locally then create the user.
            // Automatic provisioning is an optional step.
            var user = await _userManager.FindByNameAsync(ssoResult.UserID);
    
            if (user == null)
            {
                user = new IdentityUser { UserName = ssoResult.UserID, Email = ssoResult.UserID };
    
                var result = await _userManager.CreateAsync(user);
    
                if (!result.Succeeded)
                {
                    throw new Exception($&#34;The user {ssoResult.UserID} couldn&#39;t be created - {result}&#34;);
                }
    
                // For demonstration purposes, create some additional claims.
                if (ssoResult.Attributes != null)
                {
                    var samlAttribute = ssoResult.Attributes.SingleOrDefault(a =&gt; a.Name == ClaimTypes.Email);
    
                    if (samlAttribute != null)
                    {
                        await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, samlAttribute.ToString()));
                    }
    
                    samlAttribute = ssoResult.Attributes.SingleOrDefault(a =&gt; a.Name == ClaimTypes.GivenName);
    
                    if (samlAttribute != null)
                    {
                        await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.GivenName, samlAttribute.ToString()));
                    }
    
                    samlAttribute = ssoResult.Attributes.SingleOrDefault(a =&gt; a.Name == ClaimTypes.Surname);
    
                    if (samlAttribute != null)
                    {
                        await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Surname, samlAttribute.ToString()));
                    }
                }
            }
    
            // Automatically login using the asserted identity.
            await _signInManager.SignInAsync(user, isPersistent: false);
    
            // Redirect to the target URL if specified.
            if (!string.IsNullOrEmpty(ssoResult.RelayState))
            {
                return LocalRedirect(ssoResult.RelayState);
            }
    
            return RedirectToPage(&#34;/Index&#34;);
        }
    
        public async Task&lt;IActionResult&gt; SingleLogoutService()
        {
            // Receive the single logout request or response.
            // If a request is received then single logout is being initiated by the identity provider.
            // If a response is received then this is in response to single logout having been initiated by the service provider.
            var sloResult = await _samlServiceProvider.ReceiveSloAsync();
    
            if (sloResult.IsResponse)
            {
                // SP-initiated SLO has completed.
                if (!string.IsNullOrEmpty(sloResult.RelayState))
                {
                    return LocalRedirect(sloResult.RelayState);
                }
    
                return RedirectToPage(&#34;/Index&#34;);
            }
            else
            {
                // Logout locally.
                await _signInManager.SignOutAsync();
    
                // Respond to the IdP-initiated SLO request indicating successful logout.
                await _samlServiceProvider.SendSloAsync();
            }
    
            return new EmptyResult();
        }
    
        public async Task&lt;IActionResult&gt; ArtifactResolutionService()
        {
            // Resolve the HTTP artifact.
            // This is only required if supporting the HTTP-Artifact binding.
            await _samlServiceProvider.ResolveArtifactAsync();
    
            return new EmptyResult();
        }
    
        public async Task&lt;IActionResult&gt; ExportMetadata()
        {
            var entityDescriptor = await _configurationToMetadata.ExportAsync();
            var xmlElement = entityDescriptor.ToXml();
    
            Response.ContentType = &#34;text/xml&#34;;
            Response.Headers.Add(&#34;Content-Disposition&#34;, &#34;attachment; filename=\&#34;metadata.xml\&#34;&#34;);
    
            var xmlWriterSettings = new XmlWriterSettings()
            {
                Async = true,
                Encoding = Encoding.UTF8,
                Indent = true,
                OmitXmlDeclaration = true
            };
    
            using (var xmlWriter = XmlWriter.Create(Response.Body, xmlWriterSettings))
            {
                xmlElement.WriteTo(xmlWriter);
                await xmlWriter.FlushAsync();
            }
    
            return new EmptyResult();
        }
    }
    

    }

    // STARTUP:

    using ComponentSpace.Saml2.Configuration; using ComponentSpace.Saml2.Configuration.Resolver; using ComponentSpace.Saml2.Exceptions; using ExampleServiceProvider.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Shared; using System.Collections.Generic; using System.Threading.Tasks;

    namespace ExampleServiceProvider { 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&lt;ApplicationDbContext&gt;(options =&gt;
                options.UseSqlServer(
                    Configuration.GetConnectionString(&#34;DefaultConnection&#34;)));
            services.AddDefaultIdentity&lt;IdentityUser&gt;(options =&gt; options.SignIn.RequireConfirmedAccount = false)
                .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();
    
            services.AddRazorPages();
    
            services.Configure&lt;CookiePolicyOptions&gt;(options =&gt;
            {
                // SameSiteMode.None is required to support SAML SSO.
                options.MinimumSameSitePolicy = SameSiteMode.None;
    
                // Some older browsers don&#39;t support SameSiteMode.None.
                options.OnAppendCookie = cookieContext =&gt; SameSite.CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                options.OnDeleteCookie = cookieContext =&gt; SameSite.CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
            });
    
            services.ConfigureApplicationCookie(options =&gt;
            {
                // Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
                options.Cookie.Name = &#34;ExampleServiceProvider.Identity&#34;;
    
                // SameSiteMode.None is required to support SAML logout.
                options.Cookie.SameSite = SameSiteMode.None;
            });
    
            // Add SAML SSO services.
            services.AddSaml(Configuration.GetSection(&#34;SAML&#34;));
        }
    
        // 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();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler(&#34;/Error&#34;);
                // 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.UseHttpsRedirection();
            app.UseStaticFiles();
    
            app.UseRouting();
    
            app.UseCookiePolicy();
            app.UseAuthentication();
            app.UseAuthorization();
    
            app.UseEndpoints(endpoints =&gt;
            {
                endpoints.MapRazorPages();
                endpoints.MapControllers();
            });
        }
    
        // Demonstrates loading SAML configuration programmatically 
        // rather than through appsettings.json or another JSON configuration file.
        // This is useful if configuration is stored in a custom database, for example.
        // The SAML configuration is registered in ConfigureServices by calling:
        // services.AddSaml(config =&gt; ConfigureSaml(config));
        private void ConfigureSaml(SamlConfigurations samlConfigurations)
        {
            samlConfigurations.Configurations = new List&lt;SamlConfiguration&gt;()
            {
                new SamlConfiguration()
                {
                    LocalServiceProviderConfiguration = new LocalServiceProviderConfiguration()
                    {
                        Name = &#34;https://ExampleServiceProvider&#34;,
                        Description = &#34;Example Service Provider&#34;,
                        AssertionConsumerServiceUrl = &#34;https://localhost:44360/SAML/AssertionConsumerService&#34;,
                        SingleLogoutServiceUrl = &#34;https://localhost:44360/SAML/SingleLogoutService&#34;,
                        ArtifactResolutionServiceUrl = &#34;https://localhost:44360/SAML/ArtifactResolutionService&#34;,
                        LocalCertificates = new List&lt;Certificate&gt;()
                        {
                            new Certificate()
                            {
                                FileName = &#34;certificates/sp.pfx&#34;,
                                Password = &#34;password&#34;
                            }
                        }
                    },
                    PartnerIdentityProviderConfigurations = new List&lt;PartnerIdentityProviderConfiguration&gt;()
                    {
                        new PartnerIdentityProviderConfiguration()
                        {
                            Name = &#34;https://ExampleIdentityProvider&#34;,
                            Description = &#34;Example Identity Provider&#34;,
                            SignAuthnRequest = true,
                            SignLogoutRequest = true,
                            SignLogoutResponse = true,
                            WantLogoutRequestSigned = true,
                            WantLogoutResponseSigned = true,
                            SingleSignOnServiceUrl = &#34;https://localhost:44313/SAML/SingleSignOnService&#34;,
                            SingleLogoutServiceUrl = &#34;https://localhost:44313/SAML/SingleLogoutService&#34;,
                            ArtifactResolutionServiceUrl = &#34;https://localhost:44313/SAML/ArtifactResolutionService&#34;,
                            PartnerCertificates = new List&lt;Certificate&gt;()
                            {
                                new Certificate()
                                {
                                    FileName = &#34;certificates/idp.cer&#34;
                                }
                            }
                        }
                    }
                }
            };
        }
    }
    
    // Demonstrates loading SAML configuration dynamically using a custom configuration resolver.
    // Hard-coded configuration is returned in this example but more typically configuration would be read from a custom database.
    // The configurationName parameter specifies the SAML configuration in a multi-tenancy application but is not used in this example.
    // The custom configuration resolver is registered in ConfigureServices by calling:
    // services.AddSaml();
    // services.AddTransient&lt;ISamlConfigurationResolver, CustomConfigurationResolver&gt;();
    public class CustomConfigurationResolver : AbstractSamlConfigurationResolver
    {
        public override Task&lt;bool&gt; IsLocalServiceProviderAsync(string configurationName)
        {
            return Task.FromResult(true);
        }
    
        public override Task&lt;LocalServiceProviderConfiguration&gt; GetLocalServiceProviderConfigurationAsync(string configurationName)
        {
            var localServiceProviderConfiguration = new LocalServiceProviderConfiguration()
            {
                Name = &#34;https://ExampleServiceProvider&#34;,
                Description = &#34;Example Service Provider&#34;,
                AssertionConsumerServiceUrl = &#34;https://localhost:44360/SAML/AssertionConsumerService&#34;,
                SingleLogoutServiceUrl = &#34;https://localhost:44360/SAML/SingleLogoutService&#34;,
                ArtifactResolutionServiceUrl = &#34;https://localhost:44360/SAML/ArtifactResolutionService&#34;,
                LocalCertificates = new List&lt;Certificate&gt;()
                {
                    new Certificate()
                    {
                        FileName = &#34;certificates/sp.pfx&#34;,
                        Password = &#34;password&#34;
                    }
                }
            };
    
            return Task.FromResult(localServiceProviderConfiguration);
        }
    
        public override Task&lt;PartnerIdentityProviderConfiguration&gt; GetPartnerIdentityProviderConfigurationAsync(string configurationName, string partnerName)
        {
            if (partnerName != &#34;https://ExampleIdentityProvider&#34;)
            {
                throw new SamlConfigurationException($&#34;The partner identity provider {partnerName} is not configured.&#34;); 
            }
    
            var partnerIdentityProviderConfiguration = new PartnerIdentityProviderConfiguration()
            {
                Name = &#34;https://ExampleIdentityProvider&#34;,
                Description = &#34;Example Identity Provider&#34;,
                SignAuthnRequest = true,
                SignLogoutRequest = true,
                SignLogoutResponse = true,
                WantLogoutRequestSigned = true,
                WantLogoutResponseSigned = true,
                SingleSignOnServiceUrl = &#34;https://localhost:44313/SAML/SingleSignOnService&#34;,
                SingleLogoutServiceUrl = &#34;https://localhost:44313/SAML/SingleLogoutService&#34;,
                ArtifactResolutionServiceUrl = &#34;https://localhost:44313/SAML/ArtifactResolutionService&#34;,
                PartnerCertificates = new List&lt;Certificate&gt;()
                {
                    new Certificate()
                    {
                        FileName = &#34;certificates/idp.cer&#34;
                    }
                }
            };
    
            return Task.FromResult(partnerIdentityProviderConfiguration);
        }
    
        public override Task&lt;IList&lt;string&gt;&gt; GetPartnerIdentityProviderNamesAsync(string configurationName)
        {
            IList&lt;string&gt; partnerIdentityProviderNames = new List&lt;string&gt; { &#34;https://ExampleIdentityProvider&#34; };
    
            return Task.FromResult(partnerIdentityProviderNames);
        }
    }
    

    }


  5. lesponce 176 Reputation points
    2022-03-10T16:26:07.79+00:00

    Hi @Michael Taylor Thanks so much for your help. Yes, I've done the [Authorize] attribute before. The razor page was provided by the demo that I was using to mimic what I'm trying to accomplish. The redirect using Angular sounds like a good approach. I will give it a try. I'll come back to this. Thanks again.