源码下载地址:下载

项目结构如下图:

在Identity Server授权中,实现IResourceOwnerPasswordValidator接口:

  1. public class IdentityValidator : IResourceOwnerPasswordValidator
  2. {
  3. private readonly UserManager<ApplicationUser> _userManager;
  4. private readonly IHttpContextAccessor _httpContextAccessor;
  5. public IdentityValidator(
  6. UserManager<ApplicationUser> userManager,
  7. IHttpContextAccessor httpContextAccessor)
  8. {
  9. _userManager = userManager;
  10. _httpContextAccessor = httpContextAccessor;
  11. }
  12.  
  13. public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
  14. {
  15. string userName = context.UserName;
  16. string password = context.Password;
  17.  
  18. var user = await _userManager.FindByNameAsync(userName);
  19. if (user == null)
  20. {
  21. context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient, "用户不存在!");
  22. return;
  23. }
  24.  
  25. var checkResult = await _userManager.CheckPasswordAsync(user, password);
  26. if (checkResult)
  27. {
  28. context.Result = new GrantValidationResult(
  29. subject: user.Id,
  30. authenticationMethod: "custom",
  31. claims: _httpContextAccessor.HttpContext.User.Claims);
  32. }
  33. else
  34. {
  35. context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "无效的客户身份!");
  36. }
  37. }
  38. }

单页面应用中,使用implicit的授权模式,需添加oidc-client.js,调用API的关键代码:

  1. var config = {
  2. authority: "http://localhost:5000/",
  3. client_id: "JsClient",
  4. redirect_uri: "http://localhost:5500/callback.html",
  5. response_type: "id_token token",
  6. scope:"openid profile UserApi",
  7. post_logout_redirect_uri: "http://localhost:5500/index.html",
  8. };
  9. var mgr = new Oidc.UserManager(config);
  10.  
  11. mgr.getUser().then(function (user) {
  12. if (user) {
  13. log("User logged in", user.profile);
  14. }
  15. else {
  16. log("User not logged in");
  17. }
  18. });
  19.  
  20. function login() {
  21. mgr.signinRedirect();
  22. }
  23.  
  24. //api调用之前需登录
  25. function api() {
  26. mgr.getUser().then(function (user) {
  27. if (user == null || user == undefined) {
  28. login();
  29. }
  30. var url = "http://localhost:9000/api/Values";
  31.  
  32. var xhr = new XMLHttpRequest();
  33. xhr.open("GET", url);
  34. xhr.onload = function () {
  35. log(xhr.status, JSON.parse(xhr.responseText));
  36. alert(xhr.responseText);
  37. }
  38. xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
  39. xhr.setRequestHeader("sub", user.profile.sub);//这里拿到的是用户ID,传给API端进行角色权限验证
  40. xhr.send();
  41. });
  42. }
  43.  
  44. function logout() {
  45. mgr.signoutRedirect();
  46. }

统一网关通过Ocelot实现,添加Ocelot.json文件,并修改Program.cs文件:

  1. public static IWebHost BuildWebHost(string[] args) =>
  2. WebHost.CreateDefaultBuilder(args)
  3. .ConfigureAppConfiguration((hostingContext, builder) => {
  4. builder
  5. .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
  6. .AddJsonFile("Ocelot.json");
  7. })
  8. .UseUrls("http://+:9000")
  9. .UseStartup<Startup>()
  10. .Build();

StartUp.cs文件修改如下:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddOcelot();
  4.  
  5. var authenticationProviderKey = "qka_api";
  6. services.AddAuthentication("Bearer")
  7. .AddIdentityServerAuthentication(authenticationProviderKey, options =>
  8. {
  9. options.Authority = "http://localhost:5000";
  10. options.RequireHttpsMetadata = false;
  11. options.ApiName = "UserApi";
  12. });
  13.  
  14. services.AddCors(options =>
  15. {
  16. options.AddPolicy("default", policy =>
  17. {
  18. policy.AllowAnyOrigin()
  19. .AllowAnyMethod()
  20. .AllowAnyHeader()
  21. .AllowCredentials();
  22. });
  23. });
  24. }
  25.  
  26. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  27. {
  28. app.UseCors("default");
  29. app.UseOcelot().Wait();
  30. }

Ocelot.js配置文件如下:

  1. {
  2. "ReRoutes": [
  3. {
  4. "DownstreamPathTemplate": "/{url}",
  5. "DownstreamScheme": "http",
  6. "ServiceName": "userapi", //consul中的userapi的service名称
  7. "LoadBalancer": "RoundRobin", //负载均衡算法
  8. "UseServiceDiscovery": true, //启用服务发现
  9. "UpstreamPathTemplate": "/{url}",
  10. "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
  11. "AuthenticationOptions": {
  12. "AuthenticationProviderKey": "qka_api",
  13. "AllowedScopes": []
  14. }
  15. },
  16. {
  17. "DownstreamPathTemplate": "/{url}",
  18. "DownstreamScheme": "http",
  19. "ServiceName": "identityserverapi", //consul中的userapi的service名称
  20. "LoadBalancer": "RoundRobin", //负载均衡算法
  21. "UseServiceDiscovery": true, //启用服务发现
  22. "UpstreamPathTemplate": "/{url}",
  23. "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
  24. }
  25. ],
  26. "GlobalConfiguration": {
  27. "BaseUrl": "http://localhost:9000",
  28. "ServiceDiscoveryProvider": {
  29. "Host": "192.168.2.144",//consul的地址
  30. "Port": 8500//consul的端口
  31. }
  32. }
  33. }

asp.net core自带的基于角色授权需要像下图那样写死角色的名称,当角色权限发生变化时,需要修改并重新发布站点,很不方便。

所以我自定义了一个filter,实现角色授权验证:

  1. public class UserPermissionFilterAttribute : ActionFilterAttribute
  2. {
  3. public override void OnActionExecuting(ActionExecutingContext context)
  4. {
  5. if (context.Filters.Any(item => item is IAllowAnonymousFilter))
  6. {
  7. return;
  8. }
  9. if (!(context.ActionDescriptor is ControllerActionDescriptor))
  10. {
  11. return;
  12. }
  13.  
  14. var attributeList = new List<object>();
  15. attributeList.AddRange((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.GetCustomAttributes(true));
  16. attributeList.AddRange((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.DeclaringType.GetCustomAttributes(true));
  17.  
  18. var authorizeAttributes = attributeList.OfType<UserPermissionFilterAttribute>().ToList();
  19. if (!authorizeAttributes.Any())
  20. {
  21. return;
  22. }
  23.  
  24. var sub = context.HttpContext.Request.Headers["sub"];
  25. string path = context.HttpContext.Request.Path.Value.ToLower();
  26. string httpMethod = context.HttpContext.Request.Method.ToLower();
  27.  
  28. /*todo:
  29. 从数据库中根据role获取权限是否具有访问当前path和method的权限,
  30. 因调用频繁,
  31. 可考虑将角色权限缓存到redis中*/
  32. bool isAuthorized = true;
  33. if (!isAuthorized)
  34. {
  35. context.Result = new UnauthorizedResult();
  36. return;
  37. }
  38. }
  39. }

在需要授权的Action或Controller上加上该特性即可。

.net core使用Ocelot+Identity Server统一网关验证的更多相关文章

  1. (10)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- Ocelot+Identity Server

    用 JWT 机制实现验证的原理如下图:  认证服务器负责颁发 Token(相当于 JWT 值)和校验 Token 的合法性. 一. 相关概念 API 资源(API Resource):微博服务器接口. ...

  2. Asp.net core 学习笔记 ( identity server 4 JWT Part )

    更新 : id4 使用这个 DbContext 哦 dotnet ef migrations add identity-server-init --context PersistedGrantDbCo ...

  3. Asp.Net Core: Swagger 与 Identity Server 4

    Swagger不用多说,可以自动生成Web Api的接口文档和客户端调用代码,方便开发人员进行测试.通常我们只需要几行代码就可以实现这个功能: ... builder.Services.AddSwag ...

  4. 使用PostMan Canary测试受Identity Server 4保护的Web Api

    在<Asp.Net Core: Swagger 与 Identity Server 4>一文中介绍了如何生成受保护的Web Api的Swagger文档,本文介绍使用PostMan Cana ...

  5. .NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.案例结构总览 这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为 ...

  6. .net core Ocelot Consul 实现API网关 服务注册 服务发现 负载均衡

    大神张善友 分享过一篇 <.NET Core 在腾讯财付通的企业级应用开发实践>里面就是用.net core 和 Ocelot搭建的可扩展的高性能Api网关. Ocelot(http:// ...

  7. 系统集成之用户统一登录( LDAP + wso2 Identity Server)

    本文场景: LDAP + wso2 Identity Server + asp.net声明感知 场景 ,假定读者已经了解过ws-*协议族,及 ws-trust 和 ws-federation. 随着开 ...

  8. 从头编写asp.net core 2.0 web api 基础框架 (5) + 使用Identity Server 4建立Authorization Server (7) 可运行前后台源码

    前台使用angular 5, 后台是asp.net core 2.0 web api + identity server 4. 从头编写asp.net core 2.0 web api 基础框架: 第 ...

  9. ASP.NET Core Web API 索引 (更新Identity Server 4 视频教程)

    GraphQL 使用ASP.NET Core开发GraphQL服务器 -- 预备知识(上) 使用ASP.NET Core开发GraphQL服务器 -- 预备知识(下) [视频] 使用ASP.NET C ...

随机推荐

  1. Nginx常用模块安装命令

    将目录切换至Nginx安装包目录下,使用./configure命令进行安装.一些第三方模块需要先下载过来,指定下解压后的目录即可. ./configure --prefix=/usr/local/ng ...

  2. 移动web前端开发时注意事项(转)

    在智能手机横行的时代,作为一个web前端,不会编写移动web界面,的确是件悲催的事情.当公司准备做一个微信的微网站时,作为一个多年经验的web前端码农,我迷茫了,真心不知道从何下手. 接下来就是搜一堆 ...

  3. rcp perspective 添加9个视图均匀排列

    PageLayout布局方法 pageLayout.addView("NodePMTSStream" + ":1", IPageLayout.TOP, 0.5f ...

  4. 数据库面试题目- ORACLE

    Posted on 2009-06-08 17:38 漠北的天空 阅读(110) 评论(0)  编辑 收藏 1.       列举几种表连接方式 Answer:等连接(内连接).非等连接.自连接.外连 ...

  5. 教你一步步发布一个开源库到 JCenter

    今天想来分享下,如何一步步自己发布一个开源库到 JCenter 这方面的博客网上已经特别多了,所以本篇并不打算仅仅只是记录流程步骤而已,而是尽可能讲清楚,为什么需要有这个步骤,让大伙知其然的同时还知其 ...

  6. Django开发环境静态文件访问配置

    settings主要配置项目: STATIC_ROOT = 'D:\Dev\jpDev\czxg\assets' #这个地方是所在系统标准目录文法配置 STATIC_URL = '/static/' ...

  7. HashMap原理浅析

    HashMap概述 HashMap是基于哈希表和Map实现来的,它提供所有可选的映射方式,可以允许使用null键,除了不同步和允许使用null键之外,HashMap和HashTable基本上相同.因此 ...

  8. Python Tips阅读摘要

    发现了一本关于Python精通知识点的好书<Python Tips>,关于Python的进阶的技巧.摘录一些比较有价值的内容作为分享. *args and **kwargs 在函数定义的时 ...

  9. python笔记:#014#综合应用

    综合应用 -- 名片管理系统 目标 综合应用已经学习过的知识点: 变量 流程控制 函数 模块 开发 名片管理系统 系统需求 程序启动,显示名片管理系统欢迎界面,并显示功能菜单 ************ ...

  10. Nginx负载均衡和反向代理

    1:反向代理 代理就是中介,那有反向代理就有正向代理,两者的区别是什么嘞? 正向代理隐藏真实客户端,服务端不知道实际发起请求的客户端.,proxy和client同属一个LAN,对server透明: 反 ...