Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 711|回复: 0

入门教程:.NET开源OpenID Connect 和OAuth解决方案IdentityServer v3 创建简单的OAuth2.0服务器,客户端和API(三)

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-14 11:17:05 | 显示全部楼层 |阅读模式

    本教程的目的在于创造尽可能简单的identityserver安装作为一个oauth2授权服务器。这应该能够让你了解一些基本功能和配置选项(完整的源代码可以发现在这里)。在后面的文档中会介绍更多的高级功能。本教程包括:

    • 创建一个自托管identityserver

    • 设置为使用一个应用程序的帐户以及用户对通信应用的客户服务代表

    • 注册一个API

    • 请求访问令牌

    • 调用API

    • 验证一个访问令牌

    创建一个授权服务器(IdentityServer3)

    创建一个控制台应用程序,并且在程序包管理器控制台中输入

    install-package identityserver3

    注册API

    API作为请求范围,您需要注册所有您希望能够请求访问令牌的所有API,然后我们创建一个类用于返回在这个作用范围内所有的API

    using IdentityServer3.Core.Models;
    
    static class Scopes
    {
        public static List<Scope> Get()
        {
            return new List<Scope>
            {
                new Scope
                {
                    Name = "api1"
                }
            };
        }
    }

    注册客户端

    现在我们要注册一个客户端。这个客户将能够申请api1 scope的资源。对于我们的第一次迭代,将有没有人参与,客户端将简单地要求代表自己的令牌(认为机器与机器通信)。

    对于这个客户端,我们配置以下的东西:

    • 显示名称和编号(唯一的名称)

    • 客户端密钥

    • 客户端凭据 

    • 使用所谓的引用标记。参考标记不需要签名证书。

    • 允许访问的作用域("api1")

    using IdentityServer3.Core.Models;
    
    static class Clients
    {
        public static List<Client> Get()
        {
            return new List<Client>
            {
               // no human involved
                new Client
                {
                    ClientName = "Silicon-only Client",
                    ClientId = "silicon",
                    Enabled = true,
                    AccessTokenType = AccessTokenType.Reference,
    
                    Flow = Flows.ClientCredentials,
    
                    ClientSecrets = new List<Secret>
                    {
                        new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())
                    },
    
                    AllowedScopes = new List<string>
                    {
                        "api1"
                    }
                }
            };
        }
    }

     

    配置 IdentityServer

    identityserver作为OWIN的中间件的实现,它是通过UseIdentityServer扩展方法在Startup类中配置。

    下面的代码配置一个使用我们之前定义的客户端个作用域的授权服务器,稍后我们会添加用户进来。

    using Owin;
    using System.Collections.Generic;
    using IdentityServer3.Core.Configuration;
    using IdentityServer3.Core.Services.InMemory;
    
    namespace IdSrv
    {
        class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                var options = new IdentityServerOptions
                {
                    Factory = new IdentityServerServiceFactory()
                                .UseInMemoryClients(Clients.Get())
                                .UseInMemoryScopes(Scopes.Get())
                                .UseInMemoryUsers(new List<InMemoryUser>()),
                                
                    RequireSsl = false
                };
    
                app.UseIdentityServer(options);
            }
        }
    }

     

    添加日志记录

    因为我们在一个控制台中运行,它是非常方便的日志输出直接到控制台窗口。Serilog是一个很好的日志库

    install-package serilog
    install-package serilog.sinks.literate

     

    托管 IdentityServer

    最后一步是托管identityserver。在程序包管理控制台添加OWIN

    install-package Microsoft.Owin.SelfHost

     

    在Program.cs文件中添加一下代码:

    // logging
    Log.Logger = new LoggerConfiguration()
        .WriteTo
        .LiterateConsole(outputTemplate: "{Timestamp:HH:MM} [{Level}] ({Name:l}){NewLine} {Message}{NewLine}{Exception}")
        .CreateLogger();
    
    // hosting identityserver
    using (WebApp.Start<Startup>("http://localhost:5000"))
    {
        Console.WriteLine("server running...");
        Console.ReadLine();
    }

     

    然后当你启动控制台程序的时候你会看到控制台输出“server running...”

     

    添加一个 API

    在这一部分中我们将添加一个简单的Web API,我们只需要从identityserver设置一个访问令牌。

    创建API应用程序

    在的解决方案中添加一个新的ASP.NET Web API 应用程序,选择空模板

    添加必要的NuGet包:

    install-package Microsoft.Owin.Host.SystemWeb
    install-package Microsoft.AspNet.WebApi.Owin
    install-package IdentityServer3.AccessTokenValidation

    添加Controller

    添加这个简单的测试控制器:

    [Route("test")]
    public class TestController : ApiController
    {
        public IHttpActionResult Get()
        {
            var caller = User as ClaimsPrincipal;
    
            return Json(new
            {
                message = "OK computer",
                client =  caller.FindFirst("client_id").Value
            });
        }
    }

     

    控制器上的用户属性让您从访问令牌中访问该请求的权限。

    添加Startup

    添加以下Startup.cs为建立Web API和identityserver配置信任启动类

    using IdentityServer3.AccessTokenValidation;
    
    public void Configuration(IAppBuilder app)
    {
        // accept access tokens from identityserver and require a scope of 'api1'
        app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "http://localhost:5000",
                ValidationMode = ValidationMode.ValidationEndpoint,
    
                RequiredScopes = new[] { "api1" }
            });
    
        // configure web api
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();
    
        // require authentication for all controllers
        config.Filters.Add(new AuthorizeAttribute());
    
        app.UseWebApi(config);
    }

     

    试着打开浏览器,访问测试控制器-你应该看到一个401,因为必要的访问令牌丢失。

    添加Console客户端

    在下一部分中,我们将添加一个简单的控制台客户端,该客户端将请求访问令牌,并使用该接口进行身份验证。

    首先添加一个新的控制台项目并安装一oauth2客户端需要的NuGet包:

    install-package IdentityModel

     

    第一段代码 获取客户端Token使用客户端证书:

    using IdentityModel.Client;
    
    static TokenResponse GetClientToken()
    {
        var client = new TokenClient(
            "http://localhost:5000/connect/token",
            "silicon",
            "F621F470-9731-4A25-80EF-67A6F7C5F4B8");
    
        return client.RequestClientCredentialsAsync("api1").Result;
    }

     

    第二段代码 使用访问令牌调用API:

    static void CallApi(TokenResponse response)
    {
        var client = new HttpClient();
        client.SetBearerToken(response.AccessToken);
    
        Console.WriteLine(client.GetStringAsync("http://localhost:14869/test").Result);
    }

    如果你启动控制台程序,你应该看到{"message":"OK computer","client":"silicon"}在您的控制台。

    添加一个用户

    到目前为止,客户端请求一个访问令牌本身,没有用户参与。让我们介绍一个人。

    添加一个获取用户的服务

    用户服务管理用户-对于这个示例,我们将使用简单的内存用户服务。首先我们需要定义一些用户:

    using IdentityServer3.Core.Services.InMemory;
    
    static class Users
    {
        public static List<InMemoryUser> Get()
        {
            return new List<InMemoryUser>
            {
                new InMemoryUser
                {
                    Username = "bob",
                    Password = "secret",
                    Subject = "1"
                },
                new InMemoryUser
                {
                    Username = "alice",
                    Password = "secret",
                    Subject = "2"
                }
            };
        }
    }

     

    用户名和密码被用来验证用户,subject是该用户将被嵌入到访问令牌的唯一标识符。使用Users.Get()替换Startup.cs中的new List<InMemoryUser>()

    添加一个客户端

    接下来,我们将添加一个客户定义,使用流称为资源所有者的密码证书授予。此流程允许客户端将用户的用户名和密码发送到令牌服务,并在返回中获取访问令牌。

    using IdentityServer3.Core.Models;
    using System.Collections.Generic;
    
    namespace IdSrv
    {
        static class Clients
        {
            public static List<Client> Get()
            {
                return new List<Client>
                {
                    // no human involved
                    new Client
                    {
                        ClientName = "Silicon-only Client",
                        ClientId = "silicon",
                        Enabled = true,
                        AccessTokenType = AccessTokenType.Reference,
    
                        Flow = Flows.ClientCredentials,
    
                        ClientSecrets = new List<Secret>
                        {
                            new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())
                        },
    
                        AllowedScopes = new List<string>
                        {
                            "api1"
                        }
                    },
    
                    // human is involved
                    new Client
                    {
                        ClientName = "Silicon on behalf of Carbon Client",
                        ClientId = "carbon",
                        Enabled = true,
                        AccessTokenType = AccessTokenType.Reference,
    
                        Flow = Flows.ResourceOwner,
    
                        ClientSecrets = new List<Secret>
                        {
                            new Secret("21B5F798-BE55-42BC-8AA8-0025B903DC3B".Sha256())
                        },
    
                        AllowedScopes = new List<string>
                        {
                            "api1"
                        }
                    }
                };
            }
        }
    }

     

    更新API

    当涉及到人的时候,访问令牌将包含子请求以唯一标识用户。让我们对API的控制器做小的修改,:

    [Route("test")]
    public class TestController : ApiController
    {
        public IHttpActionResult Get()
        {
            var caller = User as ClaimsPrincipal;
    
            var subjectClaim = caller.FindFirst("sub");
            if (subjectClaim != null)
            {
                return Json(new
                {
                    message = "OK user",
                    client = caller.FindFirst("client_id").Value,
                    subject = subjectClaim.Value
                });
            }
            else
            {
                return Json(new
                {
                    message = "OK computer",
                    client = caller.FindFirst("client_id").Value
                });
            }
        }
    }

     

    更新客户端

    下一个向客户端添加一个新的方法,代表用户请求访问令牌:

    static TokenResponse GetUserToken()
    {
        var client = new TokenClient(
            "http://localhost:5000/connect/token",
            "carbon",
            "21B5F798-BE55-42BC-8AA8-0025B903DC3B");
    
        return client.RequestResourceOwnerPasswordAsync("bob", "secret", "api1").Result;
    }

    现在再次尝试获取token看看API返回的信息吧

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 07:21 , Processed in 0.057949 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表