zoukankan      html  css  js  c++  java
  • 05 Resource Owner Password Credentials 授权

    原文:https://www.yuque.com/yuejiangliu/dotnet/qq7lgs


    05 Resource Owner Password Credentials 授权.mp4 (93.5 MB)

    一、回顾 Client Credentials

    image.png

    • 客户端应用不代表用户,客户端应用本身就相当于资源所有者
    • 通常用于机器对机器的通信
    • 客户端也需要身份认证

    Token 请求:

    POST http://xxx/connect/token HTTP/1.1
    Accept: application/json
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 116
    Host: localhost:5000
    
    grant_type=client_credentials
    &scope=api1
    &client_id=console+client
    &client_secret=xxx

    Token 响应:

    HTTP/1.1 200 OK
    Date: Thu, 02 May 2019 03:52:13 GMT
    Content-Type: application/json; charset=UTF-8
    Server: Kestrel
    Cache-Control: no-store, no-cache, max-age=0
    Pragma: no-cache
    Transfer-Encoding: chunked
    
    {"access_token":"xxxxxx","expires_in":3600,"token_type":"Bearer"}

    可以复制 access_token 后在 jwt.io 解码查看:

    image.png

    二、Resource Owner Password Credentials

    • 资源所有者的密码凭证(例如用户名和密码)直接被用来请求 Access Token
    • 通常用于遗留的应用
    • 资源所有者和客户端应用间必须高度信任
    • 其它授权方式不可用的时候才使用,尽量不用

    1、在 IdentityServer 中配置客户端

    配置 OpenID 相关资源,并添加 WPF Client:

    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new IdentityResource[]
        {
            // 要请求下面几个 OpenID 相关的资源,必须先添加它
            new IdentityResources.OpenId(),
    
            new IdentityResources.Profile(),
            new IdentityResources.Address(),
            new IdentityResources.Phone(),
            new IdentityResources.Email()
        };
    }
    ...
    
    public static IEnumerable<Client> GetClients()
    {
        return new[]
        {
            // client credentials flow client
            ...
            // WPF client, password grant
            new Client
            {
                ClientId = "wpf client",
                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                ClientSecrets = {new Secret("wpf secret".Sha256())},
                AllowedScopes = {
                    "api1",
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    IdentityServerConstants.StandardScopes.Address,
                    IdentityServerConstants.StandardScopes.Phone}
            }
        };
    }

    测试用的 User 已定义在 TestUsers 里:

    new TestUser{SubjectId = "818727", Username = "alice", Password = "alice", 
        Claims = 
        {
            new Claim(JwtClaimTypes.Name, "Alice Smith"),
            new Claim(JwtClaimTypes.GivenName, "Alice"),
            new Claim(JwtClaimTypes.FamilyName, "Smith"),
            new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"),
            new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
            ...
        }
    },

    2、配置 WPF 客户端

    整体界面:

    image.png

    记得安装 IdentityModel。

    MainWindow 代码

    public partial class MainWindow : Window
    {
        private string _accessToken;
        private DiscoveryResponse _disco;
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private async void RequestAccessToken_ButtonClick(object sender, RoutedEventArgs e)
        {
            var userName = UserNameInput.Text;
            var password = PasswordInput.Password;
    
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000/");
            _disco = disco;
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }
    
            // request access token
            var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
            {
                Address = disco.TokenEndpoint,
                ClientId = "wpf client",
                ClientSecret = "wpf secret",
                Scope = "api1 openid profile address phone email",
    
                UserName = userName,
                Password = password
            });
    
            if (tokenResponse.IsError)
            {
                MessageBox.Show(tokenResponse.Error);
                return;
            }
    
            _accessToken = tokenResponse.AccessToken;
            AccessTokenTextBlock.Text = tokenResponse.Json.ToString();
        }
    
        private async void RequestApi1Resource_ButtonClick(object sender, RoutedEventArgs e)
        {
            // call API1 Resource
            var apiClient = new HttpClient();
            apiClient.SetBearerToken(_accessToken);
    
            var response = await apiClient.GetAsync("http://localhost:5001/identity");
            if (!response.IsSuccessStatusCode)
            {
                MessageBox.Show(response.StatusCode.ToString());
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                Api1ResponseTextBlock.Text = content;
            }
        }
    
        private async void RequestIdentityResource_ButtonClick(object sender, RoutedEventArgs e)
        {
            // call Identity Resource from Identity Server
            var apiClient = new HttpClient();
            apiClient.SetBearerToken(_accessToken);
    
            var response = await apiClient.GetAsync(_disco.UserInfoEndpoint);
            if (!response.IsSuccessStatusCode)
            {
                MessageBox.Show(response.StatusCode.ToString());
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                IdentityResponseTextBlock.Text = content;
            }
        }
    }

    3、OpenID 预设的 4 个 Scope

    5.4.  Requesting Claims using Scope Values

    • profile
    • OPTIONAL. This scope value requests access to the End-User's default profile Claims, which are: name, family_name, given_name, middle_name, nickname, preferred_username, profile, picture, website, gender, birthdate, zoneinfo, locale, and updated_at.
    • email
    • OPTIONAL. This scope value requests access to the email and email_verified Claims.
    • address
    • OPTIONAL. This scope value requests access to the address Claim.
    • phone
    • OPTIONAL. This scope value requests access to the phone_number and phone_number_verified Claims.

    4、Token 请求与响应

    Token 请求:

    POST /oauth/token HTTP/1.1
    Host:authorization-server.com
    
    grant_type=password
    &username=user@example.com
    &password=xxx
    &client_id=xxx
    &client_secret=xxx

    响应:

    {
        "access_token'; "MTQONjOkZmQ5OTM5NDE9ZTZjNGZmZjI3",
        "token_type":"bearer",
        "expires_in":3600,
    }

    5、示意图

    和 Client Credentials 相比:

    1. 多了用户角色
    2. 可以访问身份认证信息

    image.png

  • 相关阅读:
    Java学习01-使用maven插件tomcat搭建web maven项目
    Anaconda3安装及使用
    python标准日志模块logging及日志系统设计
    python traceback捕获并打印异常
    python time
    PIL 中的 Image 模块
    python zipfile使用
    PHP 判断用户是否手机访问
    php数组相加 两个数组键名相同 后者不能覆盖前者
    解决Ubuntu Server 12.04换了网卡MAC地址后 网络不可用的问题.
  • 原文地址:https://www.cnblogs.com/springsnow/p/13879207.html
Copyright © 2011-2022 走看看