asp.net權限認證:OWIN實現OAuth 2.0 之受權碼模式(Authorization Code)

受權碼模式定義

經過客戶端的後臺服務器,與「服務提供商」的認證服務器進行認證。html

一、用戶訪問客戶端,後者將前者導向認證服務器。
二、用戶選擇是否給予客戶端受權。
三、假設用戶給予受權,認證服務器首先生成一個受權碼,並返回給用戶,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個受權碼。
四、客戶端收到受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。
五、認證服務器覈對了受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。
六、Client拿着access token去訪問Resource資源api

受權碼模式的工做流程圖

圖 1 (網上搜到的受權碼工做流程圖說明)服務器

 

以前看上邊的流程圖,看了不下10遍,仍是搞不懂,這個圖真心畫的很差理解!asp.net

咱們一步步來,AuthorizationServer與ResourceServer仍是用以前的項目ide

新建項目:AuthorizationCodeGrant

 

HomeController.cs也簡單

     public ActionResult Index()
        {
            ViewBag.AccessToken = Request.Form["AccessToken"] ?? "";
            ViewBag.RefreshToken = Request.Form["RefreshToken"] ?? "";
            ViewBag.Action = "";
            ViewBag.ResourceResponse = "";

            var authorizationServerUri = new Uri("http://localhost:8270/");
            var authorizationServer = new AuthorizationServerDescription
            {
                AuthorizationEndpoint = new Uri(authorizationServerUri, "OAuth/Authorize"),
                TokenEndpoint = new Uri(authorizationServerUri, "OAuth/Token")
            };

            // 刷新AccessToken
            var client = new WebServerClient(authorizationServer, "123456", "abcdef");
            if (string.IsNullOrEmpty(ViewBag.AccessToken))
            {
                var authorizationState = client.ProcessUserAuthorization(Request);
                if (authorizationState != null)
                {
                    ViewBag.AccessToken = authorizationState.AccessToken;
                    ViewBag.RefreshToken = authorizationState.RefreshToken;
                    ViewBag.Action = Request.Path;
                }
            }

            // 受權申請
            if (!string.IsNullOrEmpty(Request.Form.Get("btnRequestAuthorize")))
            {
                var grantRequest = client.PrepareRequestUserAuthorization(new[] { "scopes1", "scopes2" });
                grantRequest.Send(HttpContext);
                Response.End();
            }
            
            // 申請資源
            if (!string.IsNullOrEmpty(Request.Form.Get("btnRequestResource")))
            {
                var resourceServerUri = new Uri("http://localhost:8001/");
                var resourceRequest = new HttpClient(client.CreateAuthorizingHandler(ViewBag.AccessToken));
                ViewBag.ResourceResponse = resourceRequest.GetStringAsync(new Uri(resourceServerUri, "api/Values")).Result;
            }

            return View();
        }

Index.cshtml

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Authorization Code Grant Client</title>
</head>
<body>
    <form id="form1" action="@ViewBag.Action" method="POST">
        <div>
            <input id="AccessToken" name="AccessToken" value="@ViewBag.AccessToken" type="hidden" />
            <input id="Authorize" name="btnRequestAuthorize" value="向認證服務器索要受權" type="submit" />
            <input id="Resource" name="btnRequestResource" value="訪問資源(Resource)" type="submit" />
        </div>
        <div>@ViewBag.ResourceResponse</div>
    </form>
</body>
</html>

運行項目  post

受權過程

點擊「向認證服務索要受權」,根據HomeController.cs文件的設置,頁面預計會跳轉到"http://localhost:8270/OAuth/Authorize"url

因此咱們須要在認證服務中新增處理受權碼模式的處理邏輯spa

在項目AuthorizationServer中新增OAuthController.cs、Authorize.cshtml.net

   public class OAuthController : Controller
    {
        public ActionResult Authorize()
        {
            if (Response.StatusCode != 200)
            {
                return View("AuthorizeError");
            }

            var authentication = HttpContext.GetOwinContext().Authentication;
            var ticket = authentication.AuthenticateAsync("Application").Result;
            var identity = ticket != null ? ticket.Identity : null;
            if (identity == null)
            {
                authentication.Challenge("Application");
                return new HttpUnauthorizedResult(); //用戶登陸憑證失效就報401錯誤,而且跳轉至AccountController中的Login中
            }

            ViewBag.IdentityName = identity.Name;
            ViewBag.Scopes = (Request.QueryString.Get("scope") ?? "").Split(' ');

            if (Request.HttpMethod == "POST")
            {
          // 點擊btnGrant就確認受權,返回token等信息 if (!string.IsNullOrEmpty(Request.Form.Get("btnGrant"))) { identity = new ClaimsIdentity(identity.Claims, "Bearer", identity.NameClaimType, identity.RoleClaimType); foreach (var scope in ViewBag.Scopes) { identity.AddClaim(new Claim("urn:oauth:scope", scope)); } authentication.SignIn(identity); } if (!string.IsNullOrEmpty(Request.Form.Get("btnOtherLogin"))) { authentication.SignOut("Application"); authentication.Challenge("Application"); return new HttpUnauthorizedResult(); } } return View(); } }
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Authorize</title>
</head>
<body>
    <h1>認證頁面</h1>
    <form method="POST">
        <p>登陸用戶:@ViewBag.IdentityName</p>
        <p>第三方應用須要你給他開放如下權限</p>
        <ul>
            @foreach (var scope in ViewBag.Scopes)
            {
                <li>@scope</li>
            }
        </ul>
        <p>
            <input type="submit" name="btnGrant" value="確認受權" />
            <input type="submit" name="btnOtherLogin" value="以不一樣用戶登陸" />
        </p>
    </form>
</body>
</html>
   public class AccountController : Controller
    {
        public ActionResult Login()
        {
            var authentication = HttpContext.GetOwinContext().Authentication;
            if (Request.HttpMethod == "POST")
            {
                // 默認用戶登陸成功
         // 生產環境須要單獨整合第三方登陸信息 var username = Request.Form["username"]; authentication.SignIn( new AuthenticationProperties { IsPersistent = true }, new ClaimsIdentity( new[] { new Claim(ClaimsIdentity.DefaultNameClaimType, username) }, "Application")); } return View(); } public ActionResult Logout() { return View(); } }

 

運行項目,成功跳轉至認證登陸頁面

 

點擊登陸,此時url地址爲:

http://localhost:8270/OAuth/Authorize?client_id=123456&redirect_uri=http%3A%2F%2Flocalhost%3A4825%2F&state=IUKeWFTR1HKi4hlzKOOPgw&scope=scopes1%20scopes2&response_type=code3d

7.1 client_id爲客戶端ID,即以前咱們在AuthorizationCodeGrant項目設置的clientID

7.2 redirect_uri、state爲以前登陸時就肯定的值

7.3 scope爲用戶肯定受權的範圍

7.4 response_type=code,即指定爲受權碼模式

確認受權

此時url有變化:http://localhost:4825/?code=efab38fc30c741a198b20663ec60869a36c6b25ff21f4c9986bcb9c9ae8d20eb&state=tjB9jXhNiHvIr4Ko9VhEkw

注意:這一步會會默認獲取Token

 

點擊訪問資源

 

徹底可以對上;

url中的code即認證服務返回的受權碼,以後Client請求Token會用這個code來交換

這個就是受權碼模式的特點的地方了

 

 

 自此,整個受權碼模式已經完畢了哦

 

asp.net權限認證系列

  1. asp.net權限認證:Forms認證
  2. asp.net權限認證:HTTP基本認證(http basic)
  3. asp.net權限認證:Windows認證
  4. asp.net權限認證:摘要認證(digest authentication)
  5. asp.net權限認證:OWIN實現OAuth 2.0 之客戶端模式(Client Credential)
  6. asp.net權限認證:OWIN實現OAuth 2.0 之密碼模式(Resource Owner Password Credential)
  7. asp.net權限認證:OWIN實現OAuth 2.0 之受權碼模式(Authorization Code)
  8. asp.net權限認證:OWIN實現OAuth 2.0 之簡化模式(Implicit)
相關文章
相關標籤/搜索