百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

IdentityServer4 (1) 客户端授权模式(Client Credentials)

connygpt 2024-10-10 05:21 7 浏览

写在前面

1、源码(.Net Core 2.2)

  git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git

2、相关章节

  2.1、《IdentityServer4 (1) 客户端授权模式(Client Credentials)》  2.2、《IdentityServer4 (2) 密码授权(Resource Owner Password)》  2.3、《IdentityServer4 (3) 授权码模式(Authorization Code)》  2.4、《IdentityServer4 (4) 静默刷新(Implicit)》  2.5、《IdentityServer4 (5) 混合模式(Hybrid)》

3、参考资料

  IdentityServer4 中文文档 http://www.identityserver.com.cn/  IdentityServer4 英文文档 https://identityserver4.readthedocs.io/en/latest/

4、流程图

  客户端授权模式是最基本的使用场景,我们需要做一个API(受保护的资源),一个客户端(访问的应用),一个IdentityServer(用来授权)

  

一、创建IdentityServer

1、用VS创建一个Web 项目

  

2、添加引用 IdentityServer4 包,下图是我已经安装好了的截图

3、添加一个配置文件(这里也可以使用json文件)

    public class IdpConfig
    {
        /// <summary>
        /// 用户认证信息
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<IdentityResource> GetApiResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Address(),
                new IdentityResources.Email(),
                new IdentityResources.Phone()
            };
        }
        /// <summary>
        /// API 资源
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApis()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1", "My API") 
            };
        }

        /// <summary>
        /// 客户端应用
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    // 客户端ID 这个很重要
                    ClientId = "client",
                    //AccessToken 过期时间,默认3600秒,注意这里直接设置5秒过期是不管用的,解决方案继续看下面 API资源添加JWT
                    //AccessTokenLifetime=5, 
                    // 没有交互性用户,使用 clientid/secret 实现认证。
                    AllowedGrantTypes = GrantTypes.ClientCredentials, 
                    // 用于认证的密码
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    // 客户端有权访问的范围(Scopes)
                    AllowedScopes = { "api1" }
                }
            };
        }
    }

4、在StartUp.cs 注册 IdentityServer4

  ConfigureServices()

    services.AddIdentityServer(options =>
    {
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
    })
      .AddDeveloperSigningCredential()//解决Keyset is missing 错误
      //.AddTestUsers(TestUsers.Users)
      //.AddInMemoryIdentityResources(IdpConfig.GetApiResources())
      .AddInMemoryApiResources(IdpConfig.GetApis())
      .AddInMemoryClients(IdpConfig.GetClients());

  Configure()方法添加使用 IdentityServer4 中间件

app.UseIdentityServer();

5、配置完成

  启动项目,访问 http://localhost:5002/.well-known/openid-configuration (我的端口号是5002) ,可以浏览 发现文档,参考下图,说明已经配置成功。

  后面客户端会使用里面的数据进行请求toke

  项目第一次启动根目录也会生成一个文件 tempkey.rsa

  

二、客户端

1、新建一个.Net Core Web 项目

  这里可以使用其他建立客户端 。例如:控制台程序、wpf 等等。需要添加 NuGet 包 IdentityModel

  

2、新建一个 Controller 用来测试访问上面的IdentityServer

  获取token,访问 http://localhost:5003/Idp/token ,提示访问成功

    public class IdpController : Controller
    { 
        private static readonly string _idpBaseUrl = "http://localhost:5002"; 
        public async Task<IActionResult> Token()
        {
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync(_idpBaseUrl);
            if (disco.IsError)
            {
                return Content("获取发现文档失败。error:" + disco.Error);
            }
            var token = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
            {
                Address = disco.TokenEndpoint,
                //ClientId、ClientSecret、Scope 这里要和 API 里定义的Client一模一样
                ClientId = "client",
                ClientSecret = "secret",
                Scope = "api1"
            });
            if (token.IsError)
            {
                return Content("获取 AccessToken 失败。error:" + disco.Error);
            } 
            return Content("获取 AccessToken 成功。Token:" + token.AccessToken);
        }  
    }

三、添加API资源

1、新建一个API项目

  我把API项目和IdentityServer 放到同一个解决方案,这个自己定,无所谓的

  API资源指的是IdentityServer IdpConfig.GetApis() 里面添加的 api1(这个api1名称随便起,但是要注意一定要保持一致)

  添加认证之后就可以测试用 AccessToken 请求资源了

2、添加JWT 认证

  StartUp.ConfigureServices()

       services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
       .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
       {
           // IdentityServer 地址
           options.Authority = "http://localhost:5002";
           //不需要https
           options.RequireHttpsMetadata = false;
           //这里要和 IdentityServer 定义的 api1 保持一致
           options.Audience = "api1";
           //token 默认容忍5分钟过期时间偏移,这里设置为0,
           //这里就是为什么定义客户端设置了过期时间为5秒,过期后仍可以访问数据
           options.TokenValidationParameters.ClockSkew = TimeSpan.Zero;
           options.Events = new JwtBearerEvents
           {
               //AccessToken 验证失败
               OnChallenge = op =>
               {
                   //跳过所有默认操作
                   op.HandleResponse();
                   //下面是自定义返回消息
                   //op.Response.Headers.Add("token", "401");
                   op.Response.ContentType = "application/json";
                   op.Response.StatusCode = StatusCodes.Status401Unauthorized;
                   op.Response.WriteAsync(JsonConvert.SerializeObject(new
                   {
                       status = StatusCodes.Status401Unauthorized,
                       msg = "token无效"
                   }));
                   return Task.CompletedTask;
               }
           };
       });

3、添加认证中间件

//这里注意 一定要在 UseMvc前面,顺序不可改变
app.UseAuthentication();

4、Controller 添加特性认证 [Authorize]

    [Route("api/[controller]")]
    [Authorize] 
    public class SuiBianController : Controller
    {
        [HttpGet]
        public string Get()
        {
            var roles = User.Claims.Where(l => l.Type == ClaimTypes.Role);
            return "访问成功,当前用户角色 " + string.Join(',', roles.Select(l => l.Value));
        }
    }

5、测试

  访问 http://localhost:5001/api/suibian ,提示 token 无效,证明我们增加认证成功

  

四、客户端测试

1、修改 IdpController, 添加一个action 访问 API资源 /api/suibian

    public class IdpController : Controller
    {
        //内存缓存 需要提前注册  services.AddMemoryCache();
        private IMemoryCache _memoryCache;
        private static readonly string _idpBaseUrl = "http://localhost:5002";
        private static readonly string _apiBaseUrl = "http://localhost:5001";
        public IdpController(IMemoryCache memoryCache)
        {
            _memoryCache = memoryCache;
        }
        public async Task<IActionResult> Token()
        {
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync(_idpBaseUrl);
            if (disco.IsError)
            {
                return Content("获取发现文档失败。error:" + disco.Error);
            }
            var token = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
            {
                Address = disco.TokenEndpoint,
                ClientId = "client",
                ClientSecret = "secret",
                Scope = "api1"
            });
            if (token.IsError)
            {
                return Content("获取 AccessToken 失败。error:" + disco.Error);
            }
            //将token 临时存储到 缓存中
            _memoryCache.Set("AccessToken", token.AccessToken);
            return Content("获取 AccessToken 成功。Token:" + token.AccessToken);
        }

        public async Task<IActionResult> SuiBian()
        {
            string token, apiurl = GetApiUrl("suibian");
            _memoryCache.TryGetValue("AccessToken", out token);
            if (string.IsNullOrEmpty(token))
            {
                return Content("token is null");
            }
            var client = new HttpClient();
            client.SetBearerToken(token);
            var response = await client.GetAsync(apiurl);
            var result = await response.Content.ReadAsStringAsync();
            if (!response.IsSuccessStatusCode)
            {
                _memoryCache.Remove("AccessToken");
                return Content(#34;获取 {apiurl} 失败。StatusCode:{response.StatusCode} \r\n Token:{token} \r\n result:{result}");
            }
            return Json(new
            {
                code = response.StatusCode,
                data = result
            });
        }

        private string GetApiUrl(string address)
        {
            return _apiBaseUrl + "/api/" + address;
        }
    }

2、请求 AccessToken

  http://localhost:5003/Idp/token ,请求成功后会将 token 存储到 cache 中

3、请求 API 资源

  http://localhost:5003/Idp/suibian ,token是直接在缓存里面取出来的

五、项目目录

原文地址:https://www.cnblogs.com/Zing/p/13361386.html

相关推荐

3分钟让你的项目支持AI问答模块,完全开源!

hello,大家好,我是徐小夕。之前和大家分享了很多可视化,零代码和前端工程化的最佳实践,今天继续分享一下最近开源的Next-Admin的最新更新。最近对这个项目做了一些优化,并集成了大家比较关注...

干货|程序员的副业挂,12个平台分享

1、D2adminD2Admin是一个完全开源免费的企业中后台产品前端集成方案,使用最新的前端技术栈,小于60kb的本地首屏js加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助...

Github标星超200K,这10个可视化面板你知道几个

在Github上有很多开源免费的后台控制面板可以选择,但是哪些才是最好、最受欢迎的可视化控制面板呢?今天就和大家推荐Github上10个好看又流行的可视化面板:1.AdminLTEAdminLTE是...

开箱即用的炫酷中后台前端开源框架第二篇

#头条创作挑战赛#1、SoybeanAdmin(1)介绍:SoybeanAdmin是一个基于Vue3、Vite3、TypeScript、NaiveUI、Pinia和UnoCSS的清新优...

搭建React+AntDeign的开发环境和框架

搭建React+AntDeign的开发环境和框架随着前端技术的不断发展,React和AntDesign已经成为越来越多Web应用程序的首选开发框架。React是一个用于构建用户界面的JavaScrip...

基于.NET 5实现的开源通用权限管理平台

??大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!??今天小编推荐一款基于.NE...

StreamPark - 大数据流计算引擎

使用Docker完成StreamPark的部署??1.基于h2和docker-compose进行StreamPark部署wgethttps://raw.githubusercontent.com/a...

教你使用UmiJS框架开发React

1、什么是Umi.js?umi,中文可发音为乌米,是一个可插拔的企业级react应用框架。你可以将它简单地理解为一个专注性能的类next.js前端框架,并通过约定、自动生成和解析代码等方式来辅助...

简单在线流程图工具在用例设计中的运用

敏捷模式下,测试团队的用例逐渐简化以适应快速的发版节奏,大家很早就开始运用思维导图工具比如xmind来编写测试方法、测试点。如今不少已经不少利用开源的思维导图组件(如百度脑图...)来构建测试测试...

【开源分享】神奇的大数据实时平台框架,让Flink&amp;Spark开发更简单

这是一个神奇的框架,让Flink|Spark开发更简单,一站式大数据实时平台!他就是StreamX!什么是StreamX大数据技术如今发展的如火如荼,已经呈现百花齐放欣欣向荣的景象,实时处理流域...

聊聊规则引擎的调研及实现全过程

摘要本期主要以规则引擎业务实现为例,陈述在陌生业务前如何进行业务深入、调研、技术选型、设计及实现全过程分析,如果你对规则引擎不感冒、也可以从中了解一些抽象实现过程。诉求从硬件采集到的数据提供的形式多种...

【开源推荐】Diboot 2.0.5 发布,自动化开发助理

一、前言Diboot2.0.5版本已于近日发布,在此次发布中,我们新增了file-starter组件,完善了iam-starter组件,对core核心进行了相关优化,让devtools也支持对IAM...

微软推出Copilot Actions,使用人工智能自动执行重复性任务

IT之家11月19日消息,微软在今天举办的Ignite大会上宣布了一系列新功能,旨在进一步提升Microsoft365Copilot的智能化水平。其中最引人注目的是Copilot...

Electron 使用Selenium和WebDriver

本节我们来学习如何在Electron下使用Selenium和WebDriver。SeleniumSelenium是ThoughtWorks提供的一个强大的基于浏览器的开源自动化测试工具...

Quick &#39;n Easy Web Builder 11.1.0设计和构建功能齐全的网页的工具

一个实用而有效的应用程序,能够让您轻松构建、创建和设计个人的HTML网站。Quick'nEasyWebBuilder是一款全面且轻巧的软件,为用户提供了一种简单的方式来创建、编辑...