You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC 5 SSO登录问题:首次访问需手动登录订阅

Got it, let's work through this SSO requirement you have. You've got a solid working SSO setup across your ASP.NET MVC 5 apps using Identity and Forms Authentication, but you need to block that automatic login for first-time visitors to an app—they have to explicitly click to log in, subscribe to the app, and behave exactly like an unauthenticated user until they do so. Since you already have shared machine keys configured, that's half the battle. Here's how to implement this:

1. Override Auto-Login by Intercepting Authentication

By default, Forms Authentication will automatically pick up the shared auth cookie and authenticate the user across apps. We need to intercept this process in each app to check if the user has an active subscription for that specific app.

Add this logic to your Global.asax.cs in each application:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    // Only run if the user is globally authenticated but might not have app access
    if (User.Identity.IsAuthenticated)
    {
        // Get the current user's ID (using Identity's extension method)
        var userId = User.Identity.GetUserId();
        // Replace CurrentAppId with a unique identifier for this application (e.g., a GUID or string like "AppInventory")
        var hasSubscription = db.UserSubscriptions.Any(u => u.UserId == userId && u.AppId == CurrentAppId);

        if (!hasSubscription)
        {
            // Sign the user out LOCALLY to reset their auth state for this app
            FormsAuthentication.SignOut();
            // Redirect to the app-specific login/subscribe page
            Response.Redirect("/Account/SubscribeLogin", false);
            Context.ApplicationInstance.CompleteRequest();
        }
    }
}
2. Build an App-Specific Login & Subscription Flow

Create a dedicated login page (e.g., SubscribeLogin.cshtml) that forces users to explicitly log in (even if they're authenticated elsewhere) and complete a subscription for the app.

Here's a sample action in your AccountController:

[HttpGet]
[AllowAnonymous]
public ActionResult SubscribeLogin(string returnUrl)
{
    // If the user somehow landed here but already has a subscription, send them to the intended page
    if (User.Identity.IsAuthenticated)
    {
        var userId = User.Identity.GetUserId();
        if (db.UserSubscriptions.Any(u => u.UserId == userId && u.AppId == CurrentAppId))
        {
            return RedirectToLocal(returnUrl);
        }
    }

    ViewBag.ReturnUrl = returnUrl;
    return View();
}

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SubscribeLogin(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    // Validate credentials using your existing Identity logic
    var user = await UserManager.FindAsync(model.Email, model.Password);
    if (user == null)
    {
        ModelState.AddModelError("", "Invalid email or password.");
        return View(model);
    }

    // Create a subscription record for this user and app
    db.UserSubscriptions.Add(new UserSubscription
    {
        UserId = user.Id,
        AppId = CurrentAppId,
        CreatedDate = DateTime.UtcNow
    });
    await db.SaveChangesAsync();

    // Now sign the user in normally—this will create the auth cookie that works with your SSO setup
    await SignInManager.SignInAsync(user, model.RememberMe, false);
    return RedirectToLocal(returnUrl);
}
3. Enforce Subscription Checks Globally

Add a custom action filter to ensure users can't bypass the subscription check by navigating directly to protected pages. This acts as a safety net alongside the Application_AuthenticateRequest logic.

public class RequiresSubscriptionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var httpContext = filterContext.HttpContext;
        if (httpContext.User.Identity.IsAuthenticated)
        {
            var userId = httpContext.User.Identity.GetUserId();
            var hasSubscription = db.UserSubscriptions.Any(u => u.UserId == userId && u.AppId == CurrentAppId);

            if (!hasSubscription)
            {
                // Redirect to the subscribe login page
                filterContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary
                    {
                        { "controller", "Account" },
                        { "action", "SubscribeLogin" },
                        { "returnUrl", httpContext.Request.Url.PathAndQuery }
                    });
            }
        }

        base.OnActionExecuting(filterContext);
    }
}

Register this filter globally in Global.asax.cs to apply it to all actions:

protected void Application_Start()
{
    // ... other startup logic
    GlobalFilters.Filters.Add(new RequiresSubscriptionAttribute());
}
4. Handle Edge Cases
  • Subscription Revocation: If a user's subscription to an app is removed, the above logic will automatically redirect them back to the SubscribeLogin page on their next visit.
  • Global Logout: Ensure your logout action signs out the user globally (using FormsAuthentication.SignOut() and AuthenticationManager.SignOut() for Identity) so they're logged out of all apps.
  • Consistent Auth Cookie Settings: Double-check that all apps share the same forms configuration in web.config (same name, path, domain if applicable) to maintain SSO functionality once the subscription is active.
5. Test the Flow
  • First visit: Access App B while logged into App A → you should be redirected to App B's SubscribeLogin page, with no automatic login.
  • After subscribing: Log in via the SubscribeLogin page, complete the subscription → you'll be logged into App B, and future visits will use SSO as normal.
  • Post-revocation: If the subscription is deleted, next visit to App B will again redirect to SubscribeLogin.

内容的提问来源于stack exchange,提问作者Sepak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:15:28