< Summary

Information
Class: ProjectTemplate.Web.Controllers.AccountController
Assembly: ProjectTemplate.Web
File(s): /home/runner/work/NetCoreApplicationTemplate/NetCoreApplicationTemplate/src/ProjectTemplate.Web/Controllers/AccountController.cs
Line coverage
96%
Covered lines: 28
Uncovered lines: 1
Coverable lines: 29
Total lines: 102
Line coverage: 96.5%
Branch coverage
87%
Covered branches: 7
Total branches: 8
Branch coverage: 87.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Login()100%44100%
Logout()75%4483.33%
AccessDenied()100%11100%

File(s)

/home/runner/work/NetCoreApplicationTemplate/NetCoreApplicationTemplate/src/ProjectTemplate.Web/Controllers/AccountController.cs

#LineLine coverage
 1using Microsoft.AspNetCore.Authentication;
 2using Microsoft.AspNetCore.Authentication.Cookies;
 3using Microsoft.AspNetCore.Authorization;
 4using Microsoft.AspNetCore.Mvc;
 5using ProjectTemplate.Web.Authentication;
 6using ProjectTemplate.Web.Models;
 7
 8namespace ProjectTemplate.Web.Controllers;
 9
 10/// <summary>
 11/// Provides actions for user authentication, including login, logout, and access denied handling.
 12/// </summary>
 13/// <remarks>This controller exposes endpoints for user authentication workflows. It supports external
 14/// authentication providers and enforces security best practices such as requiring local return URLs to prevent open
 15/// redirect vulnerabilities. Actions are decorated with appropriate authorization and anti-forgery attributes as
 16/// needed.</remarks>
 17/// <param name="schemeProvider">The authentication scheme provider used to retrieve available external authentication s
 18/// Cannot be null.</param>
 919public class AccountController(IAuthenticationSchemeProvider schemeProvider) : Controller
 20{
 921    private readonly IAuthenticationSchemeProvider _schemeProvider = schemeProvider;
 22
 23    /// <summary>
 24    /// Displays the login page and provides available external authentication providers.
 25    /// </summary>
 26    /// <remarks>This action is accessible without authentication. Only local return URLs are permitted to
 27    /// prevent open redirect vulnerabilities.</remarks>
 28    /// <param name="returnUrl">The URL to redirect to after a successful login. If null or empty, the user is redirecte
 29    /// root. Must be a local URL.</param>
 30    /// <returns>A view result that renders the login page with available external authentication providers, or a bad re
 31    /// result if the return URL is not local.</returns>
 32    [HttpGet("/Account/Login")]
 33    [AllowAnonymous]
 34    public async Task<IActionResult> Login(string? returnUrl = null)
 35    {
 536        string safeReturnUrl = string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl;
 37
 538        if (!Url.IsLocalUrl(safeReturnUrl))
 39        {
 140            return BadRequest();
 41        }
 42
 443        IReadOnlyList<AuthenticationScheme> schemes = await ExternalAuthenticationProviderSchemes
 444            .GetSelectableSchemesAsync(_schemeProvider);
 45
 446        AccountLoginViewModel model = new()
 447        {
 448            ReturnUrl = safeReturnUrl,
 449            ExternalProviders = schemes
 450                .Select(scheme => new ExternalAuthenticationProviderViewModel
 451                {
 452                    Scheme = scheme.Name,
 453                    DisplayName = scheme.DisplayName ?? scheme.Name
 454                })
 455                .OrderBy(provider => provider.DisplayName)
 456                .ToList()
 457        };
 58
 459        return View(model);
 560    }
 61
 62    /// <summary>
 63    /// Signs out the current user and redirects to the specified return URL.
 64    /// </summary>
 65    /// <remarks>This action requires an authenticated user, a valid anti-forgery token, and only accepts local URLs for
 66    /// to help prevent cross-site request forgery and open redirect vulnerabilities.</remarks>
 67    /// <param name="returnUrl">The URL to redirect to after sign-out. If null or empty, defaults to the application's r
 68    /// local URL.</param>
 69    /// <returns>A redirect result to the specified local return URL if sign-out is successful; otherwise, a bad request
 70    /// if the return URL is not local.</returns>
 71    [Authorize]
 72    [HttpPost("/Account/Logout")]
 73    [ValidateAntiForgeryToken]
 74    public async Task<IActionResult> Logout(string? returnUrl = null)
 75    {
 276        string safeReturnUrl = string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl;
 77
 278        if (!Url.IsLocalUrl(safeReturnUrl))
 79        {
 080            return BadRequest();
 81        }
 82
 283        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
 84
 285        return LocalRedirect(safeReturnUrl);
 286    }
 87
 88    /// <summary>
 89    /// Handles requests to the access denied page and returns a view indicating that the user does not have permission
 90    /// to access the requested resource.
 91    /// </summary>
 92    /// <remarks>This action is accessible to all users, including unauthenticated users. The response status
 93    /// code is set to 403 to indicate forbidden access.</remarks>
 94    /// <returns>A view result that displays the access denied page with a 403 Forbidden status code.</returns>
 95    [HttpGet("/Account/AccessDenied")]
 96    [AllowAnonymous]
 97    public IActionResult AccessDenied()
 98    {
 299        Response.StatusCode = StatusCodes.Status403Forbidden;
 2100        return View();
 101    }
 102}