在 ASP.NET Core 6 MVC 应用程序上创建 SSO(单点登录)CAS

问题描述 投票:0回答:2

我正在尝试创建一个 ASP.NET Core 6 MVC 应用程序并想要实现 CAS,但找不到方向。我收到了

GSS.Authentication.CAS
的 nuget 包,但他们没有说明或解释要做什么。我得到了
program.cs
文件部分,然后我不知道如何设置控制器。

program.cs
文件:

#pragma warning disable SA1200 // Using directives should be placed correctly
using System.Security.Claims;
using GSS.Authentication.CAS.AspNetCore;
using GSS.Authentication.CAS.Validation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.Extensions;

#pragma warning restore SA1200 // Using directives should be placed correctly

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddAuthorization(options =>
{
    // Globally Require Authenticated Users
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.Events = new CookieAuthenticationEvents
        {
            OnSigningOut = context =>
            {
                // Single Sign-Out
                var casUrl = new Uri(builder.Configuration["Authentication:CAS:ServerUrlBase"]);
                var links = context.HttpContext.RequestServices.GetRequiredService<LinkGenerator>();
                var serviceUrl = links.GetUriByPage(context.HttpContext, "/Index");
                var redirectUri = UriHelper.BuildAbsolute(
                    casUrl.Scheme,
                    new HostString(casUrl.Host, casUrl.Port),
                    casUrl.LocalPath,
                    "/logout",
                    QueryString.Create("service", serviceUrl!));

                var logoutRedirectContext = new RedirectContext<CookieAuthenticationOptions>(
                    context.HttpContext,
                    context.Scheme,
                    context.Options,
                    context.Properties,
                    redirectUri);
                context.Response.StatusCode = 204; // Prevent RedirectToReturnUrl
                context.Options.Events.RedirectToLogout(logoutRedirectContext);
                return Task.CompletedTask;
            },
        };
    })
    .AddCAS(options =>
    {
        options.CasServerUrlBase = builder.Configuration["Authentication:CAS:ServerUrlBase"];
        var protocolVersion = builder.Configuration.GetValue("Authentication:CAS:ProtocolVersion", 2); // change protocol to match your system
        if (protocolVersion != 3)
        {
            options.ServiceTicketValidator = protocolVersion switch
            {
                1 => new Cas10ServiceTicketValidator(options),
                2 => new Cas20ServiceTicketValidator(options),
                _ => null
            };
        }

        options.Events = new CasEvents
        {
            OnCreatingTicket = context =>
            {
                if (context.Identity == null)
                {
                    return Task.CompletedTask;
                }

                // Map claims from assertion
                var assertion = context.Assertion;
                context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, assertion.PrincipalName));
context.Identity.AddClaim(new Claim(ClaimTypes.Name, assertion.PrincipalName)); //This line allows you to access primary login info as User.identity.Name in cs code
                if (assertion.Attributes.TryGetValue("display_name", out var displayName))
                {
                    context.Identity.AddClaim(new Claim(ClaimTypes.Name, displayName));
                }

                if (assertion.Attributes.TryGetValue("email", out var email))
                {
                    context.Identity.AddClaim(new Claim(ClaimTypes.Email, email));
                }

                return Task.CompletedTask;
            },
            OnRemoteFailure = context =>
            {
                var failure = context.Failure;
                var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<CasEvents>>();
                if (!string.IsNullOrWhiteSpace(failure?.Message))
                {
                    logger.LogError(failure, "{Exception}", failure.Message);
                }

                context.Response.Redirect("/Account/ExternalLoginFailure");
                context.HandleResponse();
                return Task.CompletedTask;
            },
        };
    });

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");

    // 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.UseAuthentication();
app.UseAuthorization();
app.UseCookiePolicy();



app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
c# asp.net-core asp.net-core-mvc single-sign-on cas
2个回答
4
投票

所以我认为我发布的program.cs走在正确的轨道上。

下一步是创建控制器AccountController.cs

namespace {YourAppName}.Controllers {
    using System;
    using System.Diagnostics;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using OneRecordIssue6.Models;

    [AllowAnonymous]
    public class AccountController : Controller
    {
        IConfiguration configuration;

        public AccountController(IConfiguration configuration)
        {
            this.configuration = configuration;
        }

        public IActionResult Login()
        {
            string isDev = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
            if (isDev == "Development")
            {
               // if in developement, allow me to use any user choosen for testing. This shows me how different rules apply
                var simulatedUser = this.configuration.GetSection("Settings:simulatedUser").Value.ToString();
                var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, simulatedUser) }, CookieAuthenticationDefaults.AuthenticationScheme);
                var principal = new ClaimsPrincipal(identity);
                var authProperties = new AuthenticationProperties { ExpiresUtc = DateTimeOffset.UtcNow.AddSeconds(5), IsPersistent = false, RedirectUri = "/" };
                this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, authProperties);
                return this.RedirectToAction("Index", "Home");
            }
            else
            {
                return this.Challenge(new AuthenticationProperties { RedirectUri = "/" }, "CAS");
            }
        }

        public IActionResult ExternalLoginFailureModel()
        {
            this.Response.StatusCode = 500;
            return this.RedirectToAction("Error", "Home");
        }
    } }

然后确保在任何需要授权的控制器中添加

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

然后添加任何需要验证的页面或控制器

[Authorize]

(包括方括号)这将强制执行身份验证


0
投票

在创建新帖子之前,我在这里写,因为我的问题确实与此相关。

我在帐户控制器中有登录方法。我想通过调用注销控制器来断开客户端连接:您有如何实现它的示例吗?

谢谢!

© www.soinside.com 2019 - 2024. All rights reserved.