MVC 5 应用 - 实现 OAuth 授权代码流 [英] MVC 5 application - implement OAuth Authorization code flow

查看:13
本文介绍了MVC 5 应用 - 实现 OAuth 授权代码流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于本教程http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server,我创建了一个授权服务器、一个资源服务器和一个 MVC 客户端.MVC 客户端有一个控制器,它从资源服务器获取一些数据.资源服务器需要身份验证.MVC 客户端从授权服务器获取授权代码并将用户重定向到授权服务器进行身份验证.最后,MVC 客户端交换授权代码以获得访问令牌以访问资源服务器.这是 OAuth 2 协议描述的授权代码流.这工作正常.

Based on this tutorial http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server, I have created an Authorization Server, a Resource Server and a MVC Client. The MVC Client has a Controller which gets some data from the Resource Server. The Resource Server requires authentication. The MVC Clients gets an authorization code from the Authorization Server and Redirects the user to the Authorization Server for authentication. Finally the MVC Clients exchanges the authorization code for a Access token to Access the Resource Server. This is the Authorization code flow as described by the OAuth 2 protocol. This works fine.

现在,我需要让 MVC 客户端的控制器本身需要身份验证.我找不到这方面的教程.

Now, I have the requirement to make a Controller of the MVC Client itself require Authentication. I can not find a tutorial for this.

我添加了

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

到我的 Startup.Auth.cs.我假设,我需要设置重定向到授权服务器的选项.我还可以在选项上设置提供者:

to my Startup.Auth.cs. I assume, I need to setup the Options to Redirect to the Authorization Server. I can also set the Provider on the Options:

app.UseOAuthBearerAuthentication(new Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationOptions()
{
    Provider = new OAuthBearerAuthenticationProvider()
});

但我也坚持实现提供者的事件.任何人都可以指导我朝着正确的方向前进吗?或者有什么可以帮助我的教程吗?

But I am also stuck on implementing the events of the Provider. Can anybody guide me in the right direction? Or are there any tutorials which might help me?

推荐答案

我最终根据 Brock Allen 的这两篇文章得出了一个解决方案:

I ended up with a solution based on these two articles from Brock Allen:

基本思想是注册两个认证中间件.主动 Cookie 身份验证和被动 OAuthBearer 身份验证.在 Startup.Auth.cs 中,它们是这样添加的:

The fundemental idea is to register two authentication Middlewares. An active Cookie-Authentication and a passive OAuthBearer-Authentication. In Startup.Auth.cs they are added like this:

app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/ExternalLogin/Login"),
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
    AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
    AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive,
});

您还添加了一个 ExternalLogin-Controller.它的登录方法必须将用户重定向到授权服务器的登录页面以获取授权代码.您必须提供一个回调函数,您将在其中处理授权码.

You also add an ExternalLogin-Controller. Its Login-method has to redirect the user to the Login-page of your Authorization Server to get the authorization code. You have to supply a callback function where you will process the authorization code.

public async Task<ActionResult> Login(string returnUrl)
{
    if (string.IsNullOrEmpty(returnUrl) && Request.UrlReferrer != null)
        returnUrl = Server.UrlEncode(Request.UrlReferrer.PathAndQuery);

    if (Url.IsLocalUrl(returnUrl) && !string.IsNullOrEmpty(returnUrl))
        _returnUrl = returnUrl;

    //callback function
    _redirectUrl = Url.Action("AuthorizationCodeCallback", "ExternalLogin", null, Request.Url.Scheme);

    Dictionary<string, string> authorizeArgs = null;
    authorizeArgs = new Dictionary<string, string>
    {
        {"client_id", "0123456789"}
        ,{"response_type", "code"}
        ,{"scope", "read"}
        ,{"redirect_uri", _redirectUrl}
        // optional: state
    };

    var content = new FormUrlEncodedContent(authorizeArgs);
    var contentAsString = await content.ReadAsStringAsync();
    return Redirect("http://localhost:64426/oauth/authorize?" + contentAsString);
}

在您的回调函数中,您交换访问令牌(加上刷新令牌)的授权代码,挑战您的被动 OAuthBearer 身份验证中间件,并使用访问令牌作为您的 Cookie 登录.

In your callback-function you exchange the authorization code for an access token (plus refresh token) challenge your passive OAuthBearer-authentication Middleware and signin with the Access token as your Cookie.

public async Task<ActionResult> AuthorizationCodeCallback()
{
    // received authorization code from authorization server
    string[] codes = Request.Params.GetValues("code");
    var authorizationCode = "";
    if (codes.Length > 0)
        authorizationCode = codes[0];

    // exchange authorization code at authorization server for an access and refresh token
    Dictionary<string, string> post = null;
    post = new Dictionary<string, string>
    {
        {"client_id", "0123456789"}
        ,{"client_secret", "ClientSecret"}
        ,{"grant_type", "authorization_code"}
        ,{"code", authorizationCode}
        ,{"redirect_uri", _redirectUrl}
    };

    var client = new HttpClient();
    var postContent = new FormUrlEncodedContent(post);
    var response = await client.PostAsync("http://localhost:64426/token", postContent);
    var content = await response.Content.ReadAsStringAsync();

    // received tokens from authorization server
    var json = JObject.Parse(content);
    _accessToken = json["access_token"].ToString();
    _authorizationScheme = json["token_type"].ToString();
    _expiresIn = json["expires_in"].ToString();
    if (json["refresh_token"] != null)
        _refreshToken = json["refresh_token"].ToString();

    //SignIn with Token, SignOut and create new identity for SignIn
    Request.Headers.Add("Authorization", _authorizationScheme + " " + _accessToken);
    var ctx = Request.GetOwinContext();
    var authenticateResult = await ctx.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);
    ctx.Authentication.SignOut(DefaultAuthenticationTypes.ExternalBearer);
    var applicationCookieIdentity = new ClaimsIdentity(authenticateResult.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
    ctx.Authentication.SignIn(applicationCookieIdentity);

    var ctxUser = ctx.Authentication.User;
    var user = Request.RequestContext.HttpContext.User;

    //redirect back to the view which required authentication
    string decodedUrl = "";
    if (!string.IsNullOrEmpty(_returnUrl))
        decodedUrl = Server.UrlDecode(_returnUrl);

    if (Url.IsLocalUrl(decodedUrl))
        return Redirect(decodedUrl);
    else
        return RedirectToAction("Index", "Home");
}

我希望这对在其 MVC 5 应用程序中实现 OAuth 授权代码流的人有用.

I hope this is useful for someone who is implementing the OAuth authorization code flow in his MVC 5 application.

这篇关于MVC 5 应用 - 实现 OAuth 授权代码流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆