Identity Server for .NET core

    

Scenario:

Setup OAuth based authentication/authorization for ASP.NET core site

Solution:

Identity Server 4 is authentication and authorization package using JSON web tokens (JWT) and it implements  OAuth 2.0 specs.

1. NugetPackage -> dotnet add package IdentityServer4
2. IValidateAppUser

    1
    2
    3
    4
        public interface IValidateAppUser
        {
            User GetUserInfo(string name, string password);
        }

3. ValidateAppUser
    

    1
    2
    3
    4
    5
     public User GetUserInfo(string name, string password)
            {
                //call app user repo
                return new User();
            }

3. IdentityConfiguration
    

    1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    public static IEnumerable<IdentityResource> IdentityResources =>
                new List<IdentityResource>
                {
                    new IdentityResources.OpenId(),
                    new IdentityResources.Profile(),
                };
    
            public static IEnumerable<ApiResource> ApiResources()
            {
                return new List<ApiResource>
                {
                    new ApiResource("ApiResourceId", "My App")
                    {
                        ApiSecrets = new List<Secret>
                        {
                            new Secret("ApiResourceKey".Sha256())
                        },
                        Scopes =
                        {
                            "offline_access",
                        },
                        UserClaims = new[] {"sub", "userId", "name", "email", "role", "returnUrl"},
                    }
                };
            }
    
            public static IEnumerable<Client> Clients()
            {
                return new[]
                {
                    new Client
                    {
                        ClientId = "ClientId",
                        ClientSecrets =
                            {new Secret("ClientSecret".Sha256())},
    
                        AllowedGrantTypes = GrantTypes.Code,
                        RedirectUris = new List<string>(),
                        RequireConsent = false,
                        RequirePkce = false,
                        PostLogoutRedirectUris = new List<string>(),
    
                        AllowedScopes = new List<string>
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            IdentityServerConstants.StandardScopes.OfflineAccess
                        },
                        AllowOfflineAccess = true,
                        AllowAccessTokensViaBrowser = true,
    
                        AccessTokenLifetime = 5,
                        AccessTokenType = AccessTokenType.Jwt,
    
                        RefreshTokenUsage = TokenUsage.ReUse,
                        RefreshTokenExpiration = TokenExpiration.Sliding,
                    }
                };
            }
    
            public static IEnumerable<ApiScope> ApiScopes =>
                new ApiScope[]
                {
                    new ApiScope("offline_access", "My App"),
                };
        }

4.Startup.cs

    1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    public void ConfigureServices(IServiceCollection services)
            {
                //Validate user
                services.AddTransient<IValidateAppUser, ValidateAppUser>();
    
                //Repo to get user info
                services.AddTransient<IAppUserRepo, AppUserRepo>();
    
    
                services.AddIdentityServer()
                    .AddSigningCredential(X509Certificate2.CreateFromEncryptedPem("", new ReadOnlySpan<char>(), "test"))
                    .AddInMemoryIdentityResources(IdentityConfiguration.IdentityResources)
                    .AddInMemoryApiScopes(IdentityConfiguration.ApiScopes)
                    .AddInMemoryApiResources(IdentityConfiguration.ApiResources())
                    .AddInMemoryClients(IdentityConfiguration.Clients());
    
                services.AddTransient<IPersistedGrantStore, GrantStore>();
    
                services.AddOptions<KeyManagementOptions>()
                    .Configure<IServiceScopeFactory>((options, factory) =>
                    {
                        options.XmlRepository = new DBKeyRepository(factory);
                    });
    
                services.AddAuthentication("OAuthCookie")
                    .AddCookie("OAuthCookie", options =>
                    {
                        options.ExpireTimeSpan =
                            new TimeSpan(10, 0, 0);
                        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
                    });
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                app.UseIdentityServer();
                app.UseAuthentication();
                app.UseMiddleware<Handler>();
                app.UseAuthorization();
    
            }


5. AccountController

      [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Login(LoginInputModel model, string button)
            {
               .....
                if (ModelState.IsValid)
                {
                    var user = await _validateUser.GetUserInfo(model.Username, model.Password);
    
                        if (user != null)
                        {
                            var returnUrl = string.Empty;
    
                            if (model.ReturnUrl != null)
                            {
                                returnUrl = HttpUtility.ParseQueryString(model.ReturnUrl)["nonce"];
                            }
    
                            var claims = (new[]
                            {
                                new Claim("sub", user.UserId),
                                new Claim("user", user.UserId),
                                new Claim("name", user.Name),
                                new Claim("roles", user.Roles),
                                new Claim("returnUrl", (string.IsNullOrEmpty(returnUrl))
                            });
    
                            var userIdentity = new ClaimsIdentity(claims, "Claims");
                            var userPrincipal = new ClaimsPrincipal(new[] { userIdentity });
    
                            await HttpContext.SignInAsync(userPrincipal).ConfigureAwait(false);
                    }
                        
                }
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Logout(LogoutInputModel model)
            {
                // build a model so the logged out page knows what to display
                var vm = await BuildLoggedOutViewModelAsync(model.LogoutId).ConfigureAwait(false);
    
                ...
                vm.PostLogoutRedirectUri = "PostLogoutRedirectUri";
    
                if (User?.Identity.IsAuthenticated == true)
                {
                    ..
                }
    
                return View("", vm);
            }
    		
    		private async Task<LoggedOutViewModel> BuildLoggedOutViewModelAsync(string logoutId)
            {
                ..
    
                if (User?.Identity.IsAuthenticated == true)
                {
                    ..
                }
    
                return vm;
            }
    		

No comments:

Post a Comment

Move Github Sub Repository back to main repo

 -- delete .gitmodules git rm --cached MyProject/Core git commit -m 'Remove myproject_core submodule' rm -rf MyProject/Core git remo...