ASP.NET MVC基于声明的用户使用“外部”身份验证

时间:2022-01-19 03:36:53

Background

Our web applications use external authentication, in a sense that users' usernames/passwords aren't validated locally, but are being validated "outside" the web app in a central, single-sign-on type website. The authentication proof (and user's identification) becomes available via local server variables (HTTP_EMPLOYEEID, etc.). However, it's not quite external like authenticating against Google, Facebook, or another OAuth based setup. So I just wanted to make that distinction, so it doesn't collide with terms "External Logins" in ASP.NET Identity / Owin.

我们的Web应用程序使用外部身份验证,从某种意义上说,用户的用户名/密码未在本地验证,但在*单点登录类型的网站上“在Web应用程序之外”进行验证。验证证明(和用户的标识)可通过本地服务器变量(HTTP_EMPLOYEEID等)获得。但是,它不像对谷歌,Facebook或其他基于OAuth的设置进行身份验证那样外部。所以我只想做出这种区分,因此它不会与ASP.NET Identity / Owin中的“外部登录”术语发生冲突。

Problem

I'm trying to figure out a clean way to leverage the authenticated user data (from server variables) and pass it over to ASP.NET authentication. However, the user profile and role data has to be looked up against a web service before the user can be logged into the app.

我正在尝试找出一种干净的方法来利用经过身份验证的用户数据(来自服务器变量)并将其传递给ASP.NET身份验证。但是,在用户登录应用程序之前,必须针对Web服务查找用户配置文件和角色数据。

I want to use Owin and Claims-based identity, but I am not sure if I should also use ASP.NET Identity, as well, or just do a more "pure" implementation with claims. I like the idea of not reinventing the wheel, but I also don't want to force a square peg into a round hole (as the saying goes), if the way the user is identified and looked up from a web service does not fit a typical ASP.NET Identity usage.

我想使用Owin和基于声明的身份,但我不确定是否也应该使用ASP.NET身份,或者只是使用声明进行更“纯粹”的实现。我喜欢不重新发明*的想法,但是我也不想强迫方形钉进入圆孔(如上所述),如果用户被识别并从Web服务查找的方式不适合典型的ASP.NET标识用法。

For example, if I take a more purist approach, I could do something like:

例如,如果我采取更纯粹的方法,我可以做类似的事情:

// Get the current user's id
var userId = HttpContext.Current.Request.ServerVariables["HTTP_EMPLOYEEID"];

// Get profile and role data from a web service
MyUser user = MyUserService.GetUserById(userId);

// Create claims
var claims = new Claim[]
{
    new Claim(ClaimTypes.Name, user.Id),
    new Claim(ClaimTypes.Email, user.Email),
    new Claim(ClaimTypes.Role, user.Role), // there can be more roles, but you get the idea
    // etc.
};

// Establish identity and login
var identity = new ClaimsIdentity(claims, "CookieAuthentication");
HttpContext.Current.GetOwinContext().Authentication.SignIn(identity);

But I also know I could be using ASP.NET Identity (just without Entity Framework stuff), and just implement IUser, IUserStore, IRoleStore (and whatever else is minimally required), and use an existing, established framework from Microsoft for handling this. The argument would be that this is more in line with current standards, and could potentially be extended easier for other types of authentication (if, say, a local username/password, or Google/Facebook become other allowed authentication options eventually, in addition to the current, ServerVariables-based setup).

但我也知道我可以使用ASP.NET身份(只是没有实体框架的东西),只需实现IUser,IUserStore,IRoleStore(以及其他任何最低要求),并使用Microsoft现有的已建立的框架来处理这个问题。其论点是,这更符合当前标准,并且可能更容易扩展到其他类型的身份验证(如果是本地用户名/密码,或Google / Facebook最终成为其他允许的身份验证选项,除了当前的基于ServerVariables的设置)。

Any advice from people who've been down this path before? Should I treat the server variable injected data as custom middleware and leverage it via ASP.NET Identity, or just not worry about where to fit it in that world, and go in a more of a "purist" approach as described above?

那些曾经走过这条道路的人的建议是什么?我应该将服务器变量注入的数据视为自定义中间件并通过ASP.NET身份来利用它,或者只是不担心在那个世界中适合它的位置,并采用更多的“纯粹主义”方法,如上所述?

p.s. I'm using ASP.NET 4.6.1, and not the new ASP.NET Core.

附:我使用的是ASP.NET 4.6.1,而不是新的ASP.NET Core。

1 个解决方案

#1


1  

I have similar saturation. I do not want to use entire ASP.Net Identity, because I need to authenticate user again our external authentication.

我有类似的饱和度。我不想使用整个ASP.Net Identity,因为我需要再次验证用户的外部身份验证。

So I just use OWIN Claim Authentication which basically creates Authentication cookie with Claims; Similar to Form Authentication we used in the old days.

所以我只使用OWIN声明身份验证,它基本上创建了声明的身份验证cookie;与我们过去使用的表单身份验证类似。

public class OwinAuthenticationService 
{
    private readonly HttpContextBase _context;
    private const string AuthenticationType = "ApplicationCookie";

    public OwinAuthenticationService(HttpContextBase context)
    {
        _context = context;
    }

    public void SignIn(User user)
    {
        IList<Claim> claims = new List<Claim>
        {
            new Claim(ClaimTypes.Sid, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim(ClaimTypes.GivenName, user.FirstName),
            new Claim(ClaimTypes.Surname, user.LastName),
        };

        foreach (Role role in user.Roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role.Name));
        }

        ClaimsIdentity identity = new ClaimsIdentity(claims, AuthenticationType);

        IOwinContext context = _context.Request.GetOwinContext();
        IAuthenticationManager authenticationManager = context.Authentication;

        authenticationManager.SignIn(identity);
    }

    public void SignOut()
    {
        IOwinContext context = _context.Request.GetOwinContext();
        IAuthenticationManager authenticationManager = context.Authentication;

        authenticationManager.SignOut(AuthenticationType);
    }
}

Startup.cs

Note: I have Angular using both MVC and Web API, so I return 404 message for REST instead of 404 Page.

注意:我使用MVC和Web API都有Angular,因此我返回404消息而不是404 Page。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "ApplicationCookie",
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnApplyRedirect = ctx =>
                {
                    if (!IsApiRequest(ctx.Request))
                    {
                        ctx.Response.Redirect(ctx.RedirectUri);
                    }
                }
            }
        });
    }

    private static bool IsApiRequest(IOwinRequest request)
    {
        string apiPath = VirtualPathUtility.ToAbsolute("~/api/");
        return request.Uri.LocalPath.ToLower().StartsWith(apiPath);
    }
}

#1


1  

I have similar saturation. I do not want to use entire ASP.Net Identity, because I need to authenticate user again our external authentication.

我有类似的饱和度。我不想使用整个ASP.Net Identity,因为我需要再次验证用户的外部身份验证。

So I just use OWIN Claim Authentication which basically creates Authentication cookie with Claims; Similar to Form Authentication we used in the old days.

所以我只使用OWIN声明身份验证,它基本上创建了声明的身份验证cookie;与我们过去使用的表单身份验证类似。

public class OwinAuthenticationService 
{
    private readonly HttpContextBase _context;
    private const string AuthenticationType = "ApplicationCookie";

    public OwinAuthenticationService(HttpContextBase context)
    {
        _context = context;
    }

    public void SignIn(User user)
    {
        IList<Claim> claims = new List<Claim>
        {
            new Claim(ClaimTypes.Sid, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim(ClaimTypes.GivenName, user.FirstName),
            new Claim(ClaimTypes.Surname, user.LastName),
        };

        foreach (Role role in user.Roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role.Name));
        }

        ClaimsIdentity identity = new ClaimsIdentity(claims, AuthenticationType);

        IOwinContext context = _context.Request.GetOwinContext();
        IAuthenticationManager authenticationManager = context.Authentication;

        authenticationManager.SignIn(identity);
    }

    public void SignOut()
    {
        IOwinContext context = _context.Request.GetOwinContext();
        IAuthenticationManager authenticationManager = context.Authentication;

        authenticationManager.SignOut(AuthenticationType);
    }
}

Startup.cs

Note: I have Angular using both MVC and Web API, so I return 404 message for REST instead of 404 Page.

注意:我使用MVC和Web API都有Angular,因此我返回404消息而不是404 Page。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "ApplicationCookie",
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnApplyRedirect = ctx =>
                {
                    if (!IsApiRequest(ctx.Request))
                    {
                        ctx.Response.Redirect(ctx.RedirectUri);
                    }
                }
            }
        });
    }

    private static bool IsApiRequest(IOwinRequest request)
    {
        string apiPath = VirtualPathUtility.ToAbsolute("~/api/");
        return request.Uri.LocalPath.ToLower().StartsWith(apiPath);
    }
}