ASP.NET MVC 中用户授权的智能方式(无需创建 table 等)

Smart way for User Authorization (without creating table, etc.) in ASP.NET MVC

我使用外部提供商来验证我的 ASP.NET MVC 应用程序中的用户,没有任何问题。但是,我还需要授权用户以防止他们直接访问或过期访问(会话 2 分钟)。我以前使用过 ASP.NET Identity,但这次我不需要在 table 上保留用户和角色,因此我需要一个快速而好的解决方法来解决这个问题。那么,如何防止用户在未经我使用的提供商验证的情况下访问我的应用程序的索引页面。同样,我还需要检查用户最后一次操作后是否超过 2 分钟,在这种情况下,我需要将用户重定向到登录页面。我尝试使用 OWIN Cookie,但不幸的是我无法使用至少 10 种不同的方法注销用户:(

启动:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),

            //other options
            ExpireTimeSpan = TimeSpan.FromMinutes(1)
            //Provider = new CookieAuthenticationProvider(),
            //CookieName = "MyCookieName",
            //CookieHttpOnly = true
        });
    }
}

控制器:

[HttpGet]
public ActionResult Login(string code)
{
    //At this stage I want to force user to sign out, but none of the following methods work

    //method 1
    HttpContext.GetOwinContext().Authentication.SignOut("ApplicationCookie");

    //method 2
    var ctx = Request.GetOwinContext();
    var authManager = ctx.Authentication;
    authManager.SignOut("ApplicationCookie");
    //or        
    //authManager.SignOut();

    //method 3
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

    //method 4 (using only one of them at a time)
    Request.GetOwinContext().Authentication.SignOut();
    Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
    HttpContext.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);


    //check session
    var isAuthenticated = HttpContext.GetOwinContext().Authentication.User.Identity.IsAuthenticated; // >>> always returns true
    string tc = HttpContext.GetOwinContext().Authentication.User.Identity.Name; // >>> always returns name value


    //if user is authenticated via OAuth2.0
    if (user.isAuthenticated)
    {
        var claims = new[] {
        new Claim(ClaimTypes.Name, user.Name)
    };

        var identity = new ClaimsIdentity(claims, "ApplicationCookie");

        //// Add roles into claims
        //var roles = _roleService.GetByUserId(user.Id);
        //if (roles.Any())
        //{
        //    var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r.Name));
        //    identity.AddClaims(roleClaims);
        //}

        var context = Request.GetOwinContext();
        var authManager = context.Authentication;

        authManager.SignIn(new AuthenticationProperties
        { IsPersistent = false }, identity); // ??? I am not sure if IsPersistent should be true ? 

        return View();
    }

    // login failed
    return RedirectToAction("Account", "Login");
}

您需要在操作 and/or 控制器上设置 [Authorize] 属性。

而且大约只持续了2分钟。您可以在用户登录时将时间戳放入会话 cookie 中,然后构建一个中间件来在每次执行操作时检查会话值。如果会话值早于 2 分钟,则注销用户。

会话使用方法:

在启动文件中添加:

services.AddSession(options =>
{
   options.Cookie.SecurePolicy = CookieSecurePolicy.Always; 
});

app.UseSession();
//middleware for checking the 2 minute limit
app.UseMiddleware<SignoutMiddleware>();

在用户登录的任何地方添加会话:

HttpContext.Session.SetString(subjectId, DateTime.Now);

中间件:

public class SignoutMiddleware
{
    private readonly RequestDelegate _next;

    public SignoutMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {

        var sessionExpire = context.Session.GetString(context.User.GetSubjectId());
        //Do some logic here
        await _next.Invoke(context);
    }
}

至于您的代码当前用于登录的功能,您可能需要更改一些。但是如果你只是 google 一些 :)

应该会有很多教程

您可以使用实体框架,JSON Web Token (JWT) and Claims。使用 JWT 限制用户访问控制器部分的时间(天、小时、分钟)真的很容易。

您可以使用 SecurityTokenDescriptor 中的 Expires 对象来限制 JWT 的访问时间。所以在你的情况下我会做以下事情:

var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddMinutes(2),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };

Jason Watmore 使用 Role Based Auth and Secure Auth For Hashed Password in Database 为 .NET Core 完成了几个很棒的完整示例。不确定您使用的是哪个库,所以如果这对您没有帮助,如果您指定,我会帮助您。

我是你之前说的 AmirReza。

编辑

为了让 MVC 了解有关您的 JWT 的任何信息,您基本上必须告诉它 :-)。首先,从 nuget 安装 Jwt 包:

安装包Microsoft.Owin.Security.Jwt 然后打开你的 Startup.cs 文件并添加一个新函数来告诉 MVC 如何使用 JWT。在基础上,您的 Startup 看起来像:

using System.Configuration;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using Microsoft.Owin.Security.Jwt;
using Owin;

[assembly: OwinStartupAttribute(typeof(TOMS.Frontend.Startup))]
namespace TOMS.Frontend {
 public partial class Startup 
  { 
    public void Configuration(IAppBuilder app) 
     { 
      ConfigureAuth(app);
      ConfigureOAuthTokenConsumption(app);
     }

   private void ConfigureOAuthTokenConsumption(IAppBuilder app) 
    { 
     var issuer = ConfigurationManager.AppSettings["Issuer"];
     var audienceId = ConfigurationManager.AppSettings["AudienceId"];
     var audienceSecret =  TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);

您会注意到我将发行人 audienceIdaudienceSecret 放在我的 Web.config 文件中。 (这些值应该与资源服务器上的值匹配)。此外,您可能希望确保更新 System.IdentityModel.Tokens.Jwt 运行:

更新包System.IdentityModel.Tokens.Jwt 有了这些设置,您可以使用 [Authorize] 属性装饰您的控制器 Action 并玩球。

UPDATE 顺便说一下,如果您希望在 web.config 文件中添加值以便像我上面那样检索它们;只需将它们添加到 AppSettings 下:

<configuration> <appSettings> <add key="Issuer" value="YOUR_ISSUER" /> <add key="AudienceId" value="YOUR_AUDIENCEID" /> <add key="AudienceSecret" value="YOUR_AUDIENCESECRET" /> </appSettings> </configuration>

最后我使用 OWIN cookie authentication 解决了这个问题。下面是那些可能需要在 ASP.NET MVC 上使用 OWIN cookie 身份验证的代码。

另一方面,我很想将 JWT 集成到我的 ASP.NET MVC 项目中,但遗憾的是没能做到。但是,非常感谢并投票赞成对我也有帮助的答案。

启动:

public void Configuration(IAppBuilder app)
{
    ConfigureAuth(app);
}

public void ConfigureAuth(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        LogoutPath = new PathString("/Account/LogOff"),
        ExpireTimeSpan = TimeSpan.FromMinutes(5),
        SlidingExpiration = true,
        Provider = new CookieAuthenticationProvider(),
        CookieName = "YOUR_COOKIE_NAME",
        CookieHttpOnly = true,
        // !!! Using this setting "Always" causing "302 Redirect..." error while ddebugging >>>
        CookieSecure = CookieSecureOption.SameAsRequest 
    });
}

账户控制器:

public ActionResult Login()
{
    //authenticate user
    var user = db.GetUser("John");

    if (user != null)
    {
        var claims = new[] {
            new Claim(ClaimTypes.Name, user.Name),
            new Claim(ClaimTypes.Email, user.Email)
            //you can add more claims
        };

        var identity = new ClaimsIdentity(claims, "ApplicationCookie");

        // Add roles into claims
        var roles = _roleService.GetByUserId(user.Id);
        if (roles.Any())
        {
            var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r.Name));
            identity.AddClaims(roleClaims);
        }

        var context = Request.GetOwinContext();
        var authManager = context.Authentication;

        authManager.SignIn(new AuthenticationProperties
            { IsPersistent = true }, identity);

        return RedirectToAction("Index", "Home");
    }
    // login failed. 
    return RedirectToAction("Login", "Account");
}