Combine the use of authentication both for MVC pages and for Web API pages?

后端 未结 5 1481
面向向阳花
面向向阳花 2020-12-12 21:52

I have an MVC 5 web application and can login with a Login.cshtml page and get a cookie and the login works fine. But, I would like to do a login with the Web API and then (

5条回答
  •  醉梦人生
    2020-12-12 22:26

    The best way to achieve this, is to have an authorization server (a Web API generating a token) and token consumption middle-ware in your MVC project. IdentityServer should help. However I have done it like this:

    I built an authorization server using JWT with Web API and ASP.Net Identity as explained here.

    Once you do that, your Web APIs startup.cs will look like this:

     // Configures cookie auth for web apps and JWT for SPA,Mobile apps
     private void ConfigureOAuthTokenGeneration(IAppBuilder app)
     {
        // Configure the db context, user manager and role manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext(ApplicationUserManager.Create);
        app.CreatePerOwinContext(ApplicationRoleManager.Create);
    
        // Cookie for old school MVC application
        var cookieOptions = new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            CookieHttpOnly = true, // JavaScript should use the Bearer
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,                
            LoginPath = new PathString("/api/Account/Login"),
            CookieName = "AuthCookie"
        };
        // Plugin the OAuth bearer JSON Web Token tokens generation and Consumption will be here
        app.UseCookieAuthentication(cookieOptions);
    
        OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            //For Dev enviroment only (on production should be AllowInsecureHttp = false)
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/oauth/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
            Provider = new CustomOAuthProvider(),                
            AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["JWTPath"])
        };
    
        // OAuth 2.0 Bearer Access Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
    }
    

    You can find the CustomOAuthProvider and CustomJwtFormat classes here.

    I wrote a consumption logic (i.e. middleware) in all my other APIs (Resource servers) that I wanted to secure using the same token. Since you want to consume the token generated by the Web API in your MVC project, after implementing the authorization server, you need to the following:

    In your MVC app, add this in startup.cs:

    public void Configuration(IAppBuilder app)
    {
            ConfigureOAuthTokenConsumption(app);
    }
    
    private void ConfigureOAuthTokenConsumption(IAppBuilder app)
    {
        var issuer = ConfigurationManager.AppSettings["AuthIssuer"];
        string audienceid = ConfigurationManager.AppSettings["AudienceId"];
        byte[] audiencesecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);
    
        app.UseCookieAuthentication(new CookieAuthenticationOptions { CookieName = "AuthCookie" , AuthenticationType=DefaultAuthenticationTypes.ApplicationCookie });
    
        //// Api controllers with an [Authorize] attribute will be validated with JWT
        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Passive,
                AuthenticationType = "JWT",
                AllowedAudiences = new[] { audienceid },
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                {
                    new SymmetricKeyIssuerSecurityTokenProvider(issuer, audiencesecret)                           
                }
    
            });
    }
    

    In your MVC controller, when you receive the token, de-serialize it and generate a cookie from the access token:

    AccessClaims claimsToken = new AccessClaims();
    claimsToken = JsonConvert.DeserializeObject(response.Content);
    claimsToken.Cookie = response.Cookies[0].Value;               
    Request.Headers.Add("Authorization", "bearer " + claimsToken.access_token);
    var ctx = Request.GetOwinContext();
    var authenticateResult = await ctx.Authentication.AuthenticateAsync("JWT");
    ctx.Authentication.SignOut("JWT");
    var applicationCookieIdentity = new ClaimsIdentity(authenticateResult.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
    ctx.Authentication.SignIn(applicationCookieIdentity);
    

    Generate a machine key and add it in web.config of your Web API and ASP.Net MVC site.

    With this, a cookie will be created and the [Authorize] attribute in the MVC site and the Web API will honor this cookie.

    P.S. I have done this with a Web API issuing JWT (Authorization server or Auth & resource server) and was able to consume it in an ASP.Net MVC website, SPA Site built in Angular, secure APIs built in python (resource server), spring (resource server) and an Android App.

提交回复
热议问题