.net Core5.0使用IdentityServer4 进行权限控制

  IdentityServer4  ASP.NET Core的一个包含OpenID Connect和OAuth 2.0协议的框架,提供了单点登录,集中控制,API访问控制等功能。

OpenID 和 OAuth 的区别
  OpenID :Authentication,即认证,用户是谁?
  OAuth   :Authorization,即授权,用户能做哪些操作?
  OpenID Connect(OIDC):基于OAuth协议,是“认证”和“授权”的结合。
  OAuth2提供了Access Token来解决授权第三方客户端访问受保护资源的问题。 OIDC在这个基础上提供了ID Token来解决第三方客户端标识用户身份认证的问题。

授权模式应用场景(IdentityServer4,NET Core下的安全框架)

客户端模式:适用于和用户无关,机器与机器之间直接交互访问资源的场景。

POST https://api.oauth2server.com/token
grant_type    = client_credentials&
client_id        = CLIENT_ID&
client_secret = CLIENT_SECRET

密码模式:适用于当前的APP是专门为服务端设计的情况。

POST https://api.oauth2server.com/token
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID

简化模式:适用于浏览器WEB应用,支持

      • 用户认证(JavaScript 应用或传统服务端渲染的Web应用)
      • 用户认证+授权(JavaScript应用)

简化模式下ID Token和Access Token都是通过浏览器的前端通道传递的。

所以如果是传统服务端Web应用并且仅是在服务端使用Access Token的话,推荐使用Hybrid Flow。

      

授权码模式:授权码模式通过后台传输Tokens,相对于简化模式会更安全一点。

但每当考虑使用授权码模式的时候,请使用混合模式。混合模式会首先返回一个可验证的ID Token并且有更多其他特性。

        

混合模式:适用于服务器端 Web 应用程序和原生桌面/移动应用程序。

混合模式是简化模式和授权码模式的组合。混合模式下ID Token通过浏览器的前端通道传递,而Access Token和Refresh Token通过后端通道取得。

  下面直接上代码

     发布令牌服务 和 验证令牌服务 分成两个服务单独部署同时发布

     引用的包 <PackageReference Include="IdentityServer4" Version="3.1.3" />

   方式一:

     例子一的发布服务

    /// <summary>
/// 客户端模式
/// </summary>
public class ClientInitConfig
{
/// <summary>
/// 定义ApiResource
/// 这里的资源(Resources)指的就是管理的API
/// </summary>
/// <returns>多个ApiResource</returns>
public static IEnumerable<ApiResource> GetApiResources()
{
return new[]
{
new ApiResource("UserApi", "用户获取API")
};
} /// <summary>
/// 定义验证条件的Client
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new[]
{
new Client
{
ClientId = "MengLin.Shopping.Web",//客户端惟一标识
ClientSecrets = new [] { new Secret("MengLin123456".Sha256()) },//客户端密码,进行了加密
AllowedGrantTypes = GrantTypes.ClientCredentials,//Grant类型
AllowedScopes = new [] { "UserApi" },//允许访问的资源
Claims= new List<Claim>()
{
new Claim(IdentityModel.JwtClaimTypes.Role,"Admin"),
new Claim(IdentityModel.JwtClaimTypes.NickName,"豆豆爸爸"),
new Claim("EMail","menglin2010@126.com")
}
}
};
}
}
   public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()//怎么处理
.AddDeveloperSigningCredential()
.AddInMemoryClients(ClientInitConfig.GetClients())//InMemory 内存模式
.AddInMemoryApiResources(ClientInitConfig.GetApiResources());//能访问啥资源 services.AddControllers();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} //app.UseRouting(); app.UseIdentityServer(); app.UseAuthorization(); //app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllers();
//});
}
}

    例子一的验证服务:

   public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//鉴权
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
//ids4的地址,目的: 获取公钥,因为获取获取了公钥才能解密
options.Authority = "http://localhost:5000";//ids4的地址 不是本地启动的地址
options.Audience = "UserApi";
options.RequireHttpsMetadata = false; options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
//ValidAudiences = new List<string>() { "api1", "api2", "api3" }
}; IdentityModelEventSource.ShowPII = true;
}); //自定义授权--必须包含Claim client_role & 必须是Admin
services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policyBuilder => policyBuilder
.RequireAssertion(context =>
context.User.HasClaim(c => c.Type == "client_role") && context.User.Claims.First(c => c.Type.Equals("client_role")).Value.Equals("Admin")));
});
//自定义授权--必须包含Claim client_EMail & 必须qq结尾
services.AddAuthorization(options =>
{
options.AddPolicy("EMailPolicy", policyBuilder => policyBuilder
.RequireAssertion(context =>
context.User.HasClaim(c => c.Type == "client_EMail") && context.User.Claims.First(c => c.Type.Equals("client_EMail")).Value.EndsWith("@qq.com")));
}); services.AddControllers();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
namespace IdentityServer4_02.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpGet]
[Authorize(Policy = "AdminPolicy")]
public IActionResult Get()
{
return Ok("Get");
} [HttpGet]
[AllowAnonymous]
public IActionResult Index()
{
return Ok("Index");
} [HttpGet]
[Authorize(Policy = "EMailPolicy")]
public IActionResult Set()
{
return Ok("Set");
}
}
}

    

方式二:

  例子二的发布服务

   public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResourceResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers())
.AddProfileService<CustomProfileService>()
.AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>(); services.AddControllers();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseIdentityServer();
}
}
  public class Config
{
public static IEnumerable<IdentityResource> GetIdentityResourceResources()
{
var customProfile = new IdentityResource(
name: "custom.profile",
displayName: "Custom profile",
claimTypes: new[] { "role" }
);
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
customProfile
}; #region 方式二
//return new[]
//{
// new IdentityResources.OpenId(),
// new IdentityResources.Profile(),
// new IdentityResources.Email(),
// new IdentityResource
// {
// Name = "role",
// UserClaims = new List<string>{"role"}
// }
//};
#endregion
}
// scopes define the API resources in your system
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
//new ApiResource("api1", "My API")
new ApiResource("api1", "My API",new List<string>(){JwtClaimTypes.Role})
};
} // clients want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes =
{
"api1" ,
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}, // resource owner password grant client
new Client
{
ClientId = "ro.client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = {
"api1" ,
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"custom.profile"
}
} };
} public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password",
Claims = new List<Claim>(){
new Claim(JwtClaimTypes.Role,"superadmin")
}
},
new TestUser
{
SubjectId = "2",
Username = "bob",
Password = "password", Claims = new List<Claim>(){
new Claim(JwtClaimTypes.Role,"admin")
},
}
};
} }
   public class CustomProfileService : IProfileService
{
/// <summary>
/// The logger
/// </summary>
protected readonly ILogger Logger; /// <summary>
/// The users
/// </summary>
protected readonly TestUserStore Users; /// <summary>
/// Initializes a new instance of the <see cref="TestUserProfileService"/> class.
/// </summary>
/// <param name="users">The users.</param>
/// <param name="logger">The logger.</param>
public CustomProfileService(TestUserStore users, ILogger<TestUserProfileService> logger)
{
Users = users;
Logger = logger;
} /// <summary>
/// 只要有关用户的身份信息单元被请求(例如在令牌创建期间或通过用户信息终点),就会调用此方法
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public virtual Task GetProfileDataAsync(ProfileDataRequestContext context)
{
context.LogProfileRequest(Logger); //判断是否有请求Claim信息
if (context.RequestedClaimTypes.Any())
{
//根据用户唯一标识查找用户信息
var user = Users.FindBySubjectId(context.Subject.GetSubjectId());
if (user != null)
{
//调用此方法以后内部会进行过滤,只将用户请求的Claim加入到 context.IssuedClaims 集合中 这样我们的请求方便能正常获取到所需Claim context.AddRequestedClaims(user.Claims);
}
} context.LogIssuedClaims(Logger); return Task.CompletedTask;
} /// <summary>
/// 验证用户是否有效 例如:token创建或者验证
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public virtual Task IsActiveAsync(IsActiveContext context)
{
Logger.LogDebug("IsActive called from: {caller}", context.Caller); var user = Users.FindBySubjectId(context.Subject.GetSubjectId());
context.IsActive = user?.IsActive == true; return Task.CompletedTask;
}
}
   public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
/// <summary>
/// 这里为了演示我们还是使用TestUser作为数据源,
/// 正常使用此处应当传入一个 用户仓储 等可以从
/// 数据库或其他介质获取我们用户数据的对象
/// </summary>
private readonly TestUserStore _users;
private readonly ISystemClock _clock; public CustomResourceOwnerPasswordValidator(TestUserStore users, ISystemClock clock)
{
_users = users;
_clock = clock;
} /// <summary>
/// 验证
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
//此处使用context.UserName, context.Password 用户名和密码来与数据库的数据做校验
if (_users.ValidateCredentials(context.UserName, context.Password))
{
var user = _users.FindByUsername(context.UserName); //验证通过返回结果
//subjectId 为用户唯一标识 一般为用户id
//authenticationMethod 描述自定义授权类型的认证方法
//authTime 授权时间
//claims 需要返回的用户身份信息单元 此处应该根据我们从数据库读取到的用户信息 添加Claims 如果是从数据库中读取角色信息,那么我们应该在此处添加
context.Result = new GrantValidationResult(
user.SubjectId ?? throw new ArgumentException("Subject ID not set", nameof(user.SubjectId)),
OidcConstants.AuthenticationMethods.Password, _clock.UtcNow.UtcDateTime,
user.Claims);
}
else
{
//验证失败
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
}
return Task.CompletedTask;
}
}

    例子二的验证服务

   public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Audience = "api1";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;//如果不使用Https,则需要配置这个 //options.TokenValidationParameters = new TokenValidationParameters()
//{
// ValidAudiences = new List<string>() { "api1", "api2", "api3" }
// ValidateAudience = false
//}; options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
}; IdentityModelEventSource.ShowPII = true;
}); //services.AddAuthentication("Bearer")
// .AddJwtBearer("Bearer", options =>
// {
// //ids4的地址,目的: 获取公钥,因为获取获取了公钥才能解密
// options.Authority = "http://localhost:5001";
// options.Audience = "UserApi";
// options.RequireHttpsMetadata = false;
// //options.TokenValidationParameters = new TokenValidationParameters()
// //{
// // ValidAudiences = new List<string>() { "api1", "api2", "api3" }
// //};
// }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseRouting(); //app.UseCors("default"); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
namespace IdentityServer4_04.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpPost]
[Authorize]
public IActionResult Get()
{
return Ok("Get");
} [HttpGet]
[Authorize(Policy = "AdminPolicy")]
public IActionResult Gets()
{
return Ok("Gets");
} [HttpGet]
[AllowAnonymous]
public IActionResult Index()
{
return Ok("Index");
} [HttpGet]
[Authorize(Policy = "EMailPolicy")]
public IActionResult Set()
{
return Ok("Set");
} }
}

.net Core5.0使用IdentityServer4 进行权限控制的更多相关文章

  1. IdentityServer4实现Token认证登录以及权限控制

    相关知识点 不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下: 蟋蟀大神的:小菜学习编程-IdentityServer4 晓晨Master:Ide ...

  2. OAuth2.0 原理流程及其单点登录和权限控制

    2018年07月26日 07:21:58 kefeng-wang 阅读数:5468更多 所属专栏: Java微服务构架   版权声明:[自由转载-非商用-非衍生-保持署名]-转载请标明作者和出处. h ...

  3. android:Android 6.0权限控制代码封装

    新建的Activity类可以继承这个Activity,这个类封装了关于新版的权限处理相关的代码 使用方法: package com.glsite.phone; import android.conte ...

  4. yii2.0 引入权限控制插件

    权限控制:"mdmsoft/yii2-admin": "~2.0" 教程:http://www.cnblogs.com/zyf-zhaoyafei/p/5825 ...

  5. Atlas 2.1.0 实践(4)—— 权限控制

    Atlas的权限控制非常的丰富,本文将进行其支持的各种权限控制的介绍. 在atlas-application.properties配置文件中,可以设置不同权限的开关. atlas.authentica ...

  6. AgileConfig轻量级配置中心1.3.0发布,支持多用户权限控制

    AgileConfig 当初是设计给我自己用的一个工具,所以只设置了一道管理员密码,没有用户的概念.但是很多同学在使用过后都提出了需要多用户支持的建议.整个团队或者整个公司都使用同一个密码来管理非常的 ...

  7. Storm对DRPC权限控制Version1.0.1

    对Storm的DRPC进行权限控制, 并且设计相应的测试验证. 1.集群安装 请参考Storm集群安装Version1.0.1 2.使用DRPC功能 请参考Storm集群使用DRPC功能Version ...

  8. yii2.0权限控制 ACF权限

    ACF是一种通过yii\filters\AccessControl类来实现的简单授权 有两种角色 ?:未经认证的游客用户 @:已认证的用户 ACF可同过对角色设置权限控制访问 1)记得引入yii\fi ...

  9. Token认证登录以及权限控制

    IdentityServer4实现Token认证登录以及权限控制   相关知识点 不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下: 蟋蟀大神的: ...

  10. springmvc+spring+mybatis+maven项目集成shiro进行用户权限控制【转】

    项目结构:   1.maven项目的pom中引入shiro所需的jar包依赖关系 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...

随机推荐

  1. 解决-装了WPS后Windows无法预览word、Excel、PPT等的问题

    https://www.bilibili.com/read/cv10469054/ https://www.cnblogs.com/qq3285862072/p/15097970.html Windo ...

  2. keepalived检测UDP端口

    keepalived支持的健康检测方式有:HTTP_GET|SSL_GET.TCP_CHECK.SMTP_CHECK.MISC_CHECK. 由于keepalived自身并不支持udp检测,有TCP_ ...

  3. mybatis查询返回多条数据

    返回User类型的list <select id="queryAllUser" resultType="org.example.entity.User"& ...

  4. zTree异步获取,默认展开一级节点

    zTree官网 https://treejs.cn/v3/api.php 涉及到zTree的异步获取 这里主要是在setting部分的设置: setting: { ..., async: {enabl ...

  5. Visaul Studio 快捷方式

    1.删除光标所在行:Ctrl + shift + L : 2.剪切光标所在行:Ctrl + X : 3.在光标上方插入一行:Ctrl + Enter : 4.注释代码:Ctrl + K --> ...

  6. Python批量修改文件名中所包含指定关键字的文件

    1.去掉下图中各文件名中的'xx' 2.Python代码如下(仅供参考) import os, os.path, time def rename(file, keyword): #file: 需要修改 ...

  7. HCIA-ICT实战基础07-访问控制列表ACL进阶

    HCIA-ICT实战基础-访问控制列表ACL进阶 目录 二层ACL技术及配置 高级ACL的扩展使用方法及使用场景 1 二层ACL技术及配置 1.1 二层ACL概念 使用报文的以太网帧头来定义规则, 根 ...

  8. Java-ArrayList常用API

    返回值 方法 用途 boolean add(E e) 将指定的元素追加到此列表的末尾. void add(int index, E element) 在此列表中的指定位置插入指定的元素. boolea ...

  9. calibredrv 对layer做操作

    #clip.tclset L [layout create xxx.gds] $L create layer 10.0 $L create polygon 10.0 10 1000 1000 2000 ...

  10. 【七侠传】冲刺阶段--Day7

    [七侠传]冲刺阶段--Day7 团队成员 20181221曾宇涛 20181202李祎铭 20181209沙桐 20181215薛胜瀚 20181216杨越麒 20181223何家豪 20181232 ...