IdentityServer4实现Token认证登录以及权限控制
相关知识点
不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下:
蟋蟀大神的:小菜学习编程-IdentityServer4
晓晨Master:IdentityServer4
以及Identity,Claim等相关知识:
Savorboard:ASP.NET Core 之 Identity 入门(一),ASP.NET Core 之 Identity 入门(二)
创建IndentityServer4 服务
创建一个名为QuickstartIdentityServer的ASP.NET Core Web 空项目(asp.net core 2.0),端口5000


NuGet包:

修改Startup.cs 设置使用IdentityServer:
public class Startup
{
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())
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
.AddProfileService<ProfileService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
}
}
添加Config.cs配置IdentityResource,ApiResource以及Client:
public class Config
{
public static IEnumerable<IdentityResource> GetIdentityResourceResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(), //必须要添加,否则报无效的scope错误
new IdentityResources.Profile()
};
}
// scopes define the API resources in your system
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
}
// clients want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "client1",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "api1",IdentityServerConstants.StandardScopes.OpenId, //必须要添加,否则报forbidden错误
IdentityServerConstants.StandardScopes.Profile},
},
// resource owner password grant client
new Client
{
ClientId = "client2",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "api1",IdentityServerConstants.StandardScopes.OpenId, //必须要添加,否则报forbidden错误
IdentityServerConstants.StandardScopes.Profile }
}
};
}
}
因为要使用登录的时候要使用数据中保存的用户进行验证,要实IResourceOwnerPasswordValidator接口:
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public ResourceOwnerPasswordValidator()
{
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
//根据context.UserName和context.Password与数据库的数据做校验,判断是否合法
if (context.UserName=="wjk"&&context.Password=="123")
{
context.Result = new GrantValidationResult(
subject: context.UserName,
authenticationMethod: "custom",
claims: GetUserClaims());
}
else
{
//验证失败
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
}
}
//可以根据需要设置相应的Claim
private Claim[] GetUserClaims()
{
return new Claim[]
{
new Claim("UserId", 1.ToString()),
new Claim(JwtClaimTypes.Name,"wjk"),
new Claim(JwtClaimTypes.GivenName, "jaycewu"),
new Claim(JwtClaimTypes.FamilyName, "yyy"),
new Claim(JwtClaimTypes.Email, "977865769@qq.com"),
new Claim(JwtClaimTypes.Role,"admin")
};
}
}
IdentityServer提供了接口访问用户信息,但是默认返回的数据只有sub,就是上面设置的subject: context.UserName,要返回更多的信息,需要实现IProfileService接口:
public class ProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
try
{
//depending on the scope accessing the user data.
var claims = context.Subject.Claims.ToList();
//set issued claims to return
context.IssuedClaims = claims.ToList();
}
catch (Exception ex)
{
//log your error
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
context.IsActive = true;
}
context.Subject.Claims就是之前实现IResourceOwnerPasswordValidator接口时claims: GetUserClaims()给到的数据。
另外,经过调试发现,显示执行ResourceOwnerPasswordValidator 里的ValidateAsync,然后执行ProfileService 里的IsActiveAsync,GetProfileDataAsync。
启动项目,使用postman进行请求就可以获取到token:

再用token获取相应的用户信息:

token认证服务一般是与web程序分开的,上面创建的QuickstartIdentityServer项目就相当于服务端,我们需要写业务逻辑的web程序就相当于客户端。当用户请求web程序的时候,web程序拿着用户已经登录取得的token去IdentityServer服务端校验。
创建web应用
创建一个名为API的ASP.NET Core Web 空项目(asp.net core 2.0),端口5001。
NuGet包:

修改Startup.cs 设置使用IdentityServer进行校验:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore(option=>
{
option.Filters.Add(new TestAuthorizationFilter());
}).AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
});
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseMvc();
}
}
创建IdentityController:
[Route("[controller]")]
public class IdentityController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get()
{
return new JsonResult("Hello Word");
}
}
分别运行QuickstartIdentityServer,API项目。用生成的token访问API:

通过上述程序,已经可以做一个前后端分离的登录功能。
实际上,web应用程序中我们经常需要获取当前用户的相关信息进行操作,比如记录用户的一些操作日志等。之前说过IdentityServer提供了接口/connect/userinfo来获取用户的相关信息。之前我的想法也是web程序中拿着token去请求这个接口来获取用户信息,并且第一次获取后做相应的缓冲。但是感觉有点怪怪的,IdentityServer不可能没有想到这一点,正常的做法应该是校验通过会将用户的信息返回的web程序中。问题又来了,如果IdentityServer真的是这么做的,web程序该怎么获取到呢,查了官方文档也没有找到。然后就拿着"Claim"关键字查了一通(之前没了解过ASP.NET Identity),最后通过HttpContext.User.Claims取到了设置的用户信息:
修改IdentityController :
[Route("[controller]")]
public class IdentityController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get()
{
return new JsonResult(from c in HttpContext.User.Claims select new { c.Type, c.Value });
}
}

权限控制
IdentityServer4 也提供了权限管理的功能,大概看了一眼,没有达到我想要(没耐心去研究)。
我需要的是针对不同的模块,功能定义权限码(字符串),每个权限码对应相应的功能权限。当用户进行请求的时候,判断用户是否具备相应功能的权限(是否赋予了相应的权限字符串编码),来达到权限控制。
IdentityServer的校验是通过Authorize特性来判断相应的Controller或Action是否需要校验。这里也通过自定义特性来实现权限的校验,并且是在原有的Authorize特性上进行扩展。可行的方案继承AuthorizeAttribute,重写。可是在.net core中提示没有OnAuthorization方法可进行重写。最后参考的ABP的做法,过滤器和特性共同使用。
新建TestAuthorizationFilter.cs
public class TestAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
{
return;
}
if (!(context.ActionDescriptor is ControllerActionDescriptor))
{
return;
}
var attributeList = new List<object>();
attributeList.AddRange((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.GetCustomAttributes(true));
attributeList.AddRange((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.DeclaringType.GetCustomAttributes(true));
var authorizeAttributes = attributeList.OfType<TestAuthorizeAttribute>().ToList();
var claims = context.HttpContext.User.Claims;
// 从claims取出用户相关信息,到数据库中取得用户具备的权限码,与当前Controller或Action标识的权限码做比较
var userPermissions = "User_Edit";
if (!authorizeAttributes.Any(s => s.Permission.Equals(userPermissions)))
{
context.Result = new JsonResult("没有权限");
}
return;
}
}
新建TestAuthorizeAttribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class TestAuthorizeAttribute: AuthorizeAttribute
{
public string Permission { get; set; }
public TestAuthorizeAttribute(string permission)
{
Permission = permission;
}
}
将IdentityController [Authorize]改为[TestAuthorize("User_Edit")],再运行API项目。
通过修改权限码,验证是否起作用

除了使用过滤器和特性结合使用,貌似还有别的方法,有空再研究。
本文中的源码
IdentityServer4实现Token认证登录以及权限控制的更多相关文章
- Token认证登录以及权限控制
IdentityServer4实现Token认证登录以及权限控制 相关知识点 不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下: 蟋蟀大神的: ...
- 手工搭建基于ABP的框架(3) - 登录,权限控制与日志
为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7695258.html 本篇将实现登录.权限控制.日志配置与审计日志的功能.首先我 ...
- 七、spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
1.安装cas-server-3.5.2 官网:https://github.com/apereo/cas/releases/tag/v3.5.2 下载地址:cas-server-3.5.2-rele ...
- OAuth2.0 原理流程及其单点登录和权限控制
2018年07月26日 07:21:58 kefeng-wang 阅读数:5468更多 所属专栏: Java微服务构架 版权声明:[自由转载-非商用-非衍生-保持署名]-转载请标明作者和出处. h ...
- Spring Security实现统一登录与权限控制
1 项目介绍 最开始是一个单体应用,所有功能模块都写在一个项目里,后来觉得项目越来越大,于是决定把一些功能拆分出去,形成一个一个独立的微服务,于是就有个问题了,登录.退出.权限控制这些东西怎么办呢? ...
- .net core 同时实现网站管理员后台、会员、WebApi登录及权限控制
我们在开网站信息系统时,常常有这样几个角色,如后台的管理员,前台的会员,以及我们各种应用的WebAPI 都需要进行登录操作及权限控制,那么在.net core如何进行设计呢. 首先我使用的是.net ...
- Shrio00 Shiro认证登录、权限管理环境搭建
基础环境准备: JDK -> java version "1.8.0_101" MAVEN -> Apache Maven 3.5.0 1 导入依赖 mysql驱动 m ...
- Spring+MyBatis实践—登录和权限控制
1.实现用户登录功能: 通过session来实现用户登录功能.在用户登录时,将用户的相关信息放在HttpSession对象用,其中HttpSession对象可以通过HttpServletRequest ...
- aProxy: 带认证授权和权限控制的反向代理
前段时间很多数据库因为没有做好权限控制暴露在外网被删然后遭勒索的事件,而类似的有些内网的web服务也会被开放到公网并且没有做任何权限控制的,这样也会有一定的风险.所以就决定写篇文章简单介绍一个小工具. ...
随机推荐
- java 线程一
java基础学习总结--线程(一) 一.线程的基本概念 线程理解:线程是一个程序里面不同的执行路径 每一个分支都叫做一个线程,main()叫做主分支,也叫主线程. 程只是一个静态的概念,机器上的一个. ...
- JVM读书笔记PART3
一.早期(编译器)优化 语法糖 c#和java的泛型截然不同看似相同,c#是真实的泛型 编译运行一直存在 List<string> 和List<int> 就完全是两个类 而Ja ...
- Java EE开发环境——MyEclipse2017破解 和 Tomcat服务器配置
Java EE开发,我们可以搭建如下开发环境: 底层运行环境:jdk 和 jre. Web服务器:Tomcat 后台数据库:SQL Server 可视化集成开发环境:MyEclipse Java EE ...
- Codecraft-17 and Codeforces Round #391 (Div. 1 + Div. 2, combined)D. Felicity's Big Secret Revealed
题目连接:http://codeforces.com/contest/757/problem/D D. Felicity's Big Secret Revealed time limit per te ...
- ARCGIS切图:TPK文件的空间参考为地理坐标系
先来吐槽一下,之前习惯了百度地图API,所以一直习惯直接将经纬度点添加到地图上进行显示,目前使用ARCGIS RUNTIME FOR ANDROID进行开发,在地图上加点需要原始点的坐标为投影坐标系, ...
- MMORPG战斗系统随笔(三)、AI系统简介
在设计一款游戏的时候,如果我们是玩家,是希望自己能够操作角色畅玩游戏的.在一款MMORPG游戏中,大部分的实际游戏角色,是需要玩家来操作的,通过在游戏大世界相互完成游戏中的任务等等来体验游戏.在大世界 ...
- ASP.NET没有魔法——ASP.NET MVC & 分层
上一篇文章简要说明了MVC所代表的含义并提供了详细的项目及其控制器.视图等内容的创建步骤,最终完成了一个简单ASP.NET MVC程序. 注:MVC与ASP.NET MVC不相等,MVC是一种开发模式 ...
- Python自学笔记-map和reduce函数(来自廖雪峰的官网Python3)
感觉廖雪峰的官网http://www.liaoxuefeng.com/里面的教程不错,所以学习一下,把需要复习的摘抄一下. 以下内容主要为了自己复习用,详细内容请登录廖雪峰的官网查看. Python内 ...
- vue2购物车ch1-(安装依赖、简单配置、 axios获取api的模拟数据)
0--项目说明 说明此项目源自某课网购物车教程,但是在开发过程中,发现在开发过程中用的还是 vue-resource(宣布不更新的类$.ajx()插件),为了以后的发展使用axios.js,详情参考 ...
- ORALCE PL/SQL学习笔记
ORALCE PL/SQL学习笔记 详情见自己电脑的备份数据资料