asp.net-mvc - 当MVC和Web API在不同的项目中时如何存储不记名 token

标签 asp.net-mvc cookies asp.net-web-api oauth-2.0 bearer-token

情况:
我有一个 Web API 2 项目,它充当授权服务器(/ token 端点)和资源服务器。我正在使用随 ASP.Net Web API 一起开箱即用的模板,减去任何 MVC 引用。
Start.Auth 配置如下:

public void ConfigureAuth(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Configure the application for OAuth based flow
            PublicClientId = "self";
            OAuthOptions = new OAuthAuthorizationServerOptions
            {
                TokenEndpointPath = new PathString("/Token"),
                Provider = new ApplicationOAuthProvider(PublicClientId),
                AuthorizeEndpointPath = new PathString("/Account/ExternalLogin"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                // In production mode set AllowInsecureHttp = false
                AllowInsecureHttp = true
            };

            // Enable the application to use bearer tokens to authenticate users
            app.UseOAuthBearerTokens(OAuthOptions);

            var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
            {
                AppId = ConfigurationManager.AppSettings["Test_Facebook_AppId"],
                AppSecret = ConfigurationManager.AppSettings["Test_Facebook_AppSecret"],
                //SendAppSecretProof = true,
                Provider = new FacebookAuthenticationProvider
                {
                    OnAuthenticated = (context) =>
                    {
                        context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
                        return Task.FromResult(0);
                    }
                }
            };

            facebookAuthenticationOptions.Scope.Add("email user_about_me user_location");
            app.UseFacebookAuthentication(facebookAuthenticationOptions);

        }

MVC 5 客户端(不同的项目)使用 Web API 应用程序进行授权和数据。以下是在用户名/密码存储的情况下检索不记名 token 的代码:
[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            model.ExternalProviders = await GetExternalLogins(returnUrl);
            return View(model);
        }

        var client = Client.GetClient();

        var response = await client.PostAsync("Token", 
            new StringContent(string.Format("grant_type=password&username={0}&password={1}", model.Email, model.Password), Encoding.UTF8));

        if (response.IsSuccessStatusCode)
        {
            return RedirectToLocal(returnUrl);
        }
        return View();
    }

问题

我可以检索 Bearer token ,然后将其添加到 Authorization Header 以供后续调用。我认为在 Angular 应用程序或 SPA 的情况下没问题。但我认为 MVC 中应该有一些东西可以为我处理它,比如自动将它存储在 cookie 中并在后续请求中发送 cookie。我已经搜索了很多东西,有一些帖子暗示了这一点( Registering Web API 2 external logins from multiple API clients with OWIN Identity ),但我无法弄清楚在获得 token 后该怎么做。

我需要在 MVC 应用程序 Startup.Auth 中添加一些东西吗?

理想情况下,我需要 ASP.Net 模板(MVC + Web API)中的 AccountController 提供开箱即用的功能(登录、注册、外部登录、忘记密码等...)但在不同项目中使用 MVC 和 Web API .

是否有包含此样板代码的模板或 git repo?

提前致谢!

更新
结合@FrancisDucharme 的建议,下面是 GrantResourceOwnerCredentials() 的代码。
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

            ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }

            ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
               OAuthDefaults.AuthenticationType);
            ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
                CookieAuthenticationDefaults.AuthenticationType);

            AuthenticationProperties properties = CreateProperties(user.UserName);
            AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);

            //Add a response cookie...
            context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));


            context.Validated(ticket);
            context.Request.Context.Authentication.SignIn(cookiesIdentity);
        }

但我似乎仍然无法获得那个 Cookie 或弄清楚下一步该做什么。

重述问题:
  • 从 MVC 客户端进行身份验证、授权和调用 Web API 方法(身份验证和资源服务器)的正确方法是什么?
  • 是否有 AccountController 的样板代码或模板来执行基本的管道操作(登录、注册 - 内部/外部、忘记密码等)?
  • 最佳答案

    您可以让您的 Startup 类返回一个响应 cookie,然后客户端将在所有后续请求中返回该响应 cookie,这是一个示例。我会在 GrantResourceOwnerCredentials 做.

    public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
    
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }
    
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {                          
    
            //your authentication logic here, if it fails, do this...
            //context.SetError("invalid_grant", "The user name or password is incorrect.");
            //return;
    
             var identity = new ClaimsIdentity(context.Options.AuthenticationType);
             identity.AddClaim(new Claim("sub", context.UserName));
             identity.AddClaim(new Claim("role", "user"));
    
             AuthenticationTicket ticket = new AuthenticationTicket(identity);
    
            //Add a response cookie...
            context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));
    
            context.Validated(ticket);
    
    }
    

    启动类:
    public partial class Startup
    {
    
        public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
    
        public Startup()
        {
            OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        }
    
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
    
            ConfigureOAuth(app);
            //I use CORS in my projects....
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
    
            WebApiConfig.Register(config);
    
        }
    
        public void ConfigureOAuth(IAppBuilder app)
        {
            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true, //I have this here for testing purpose, production should always only accept HTTPS encrypted traffic.
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                Provider = new AuthorizationServerProvider()
            };
    
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(OAuthBearerOptions);
    
        }
    }
    

    当然,这假设客户端启用了 cookie。

    然后,modify your MVC headers将 Authorization header 添加到所有请求中。

    ActionFilterAttribute , 获取您的 cookie 值 ( Token ) 并添加标题。

    关于asp.net-mvc - 当MVC和Web API在不同的项目中时如何存储不记名 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34674707/

    相关文章:

    asp.net - 仅返回 Web API 结果中选定的字段

    asp.net-mvc - 添加多对多关系,无需从数据库中获取子实体

    asp.net-mvc - 用于 CSS 背景图像的 ASP.Net 开发服务器 SVG 文件服务

    c# - CS0234 : The type or namespace name 'WebPages' does not exist in the namespace 'System.Web' (are you missing an assembly reference? )

    javascript - "The owner of this website has banned your access based on your browser' s signature"...在 python 程序中的 url 请求

    php - 客户计算机上创建的 cookie 在哪里

    c# - 在 Web Api 2 中向链接 header 添加分页

    sql-server - 让 IIS 在内网环境中模拟 Windows 用户访问 SQL Server

    asp.net - Ninject 给出 NullReferenceException

    javascript - (node.js) 如何从远程服务器获取cookie?