Token认证登录以及权限控制
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项目。
通过修改权限码,验证是否起作用
除了使用过滤器和特性结合使用,貌似还有别的方法,有空再研究。
本文中的源码
Token认证登录以及权限控制的更多相关文章
- IdentityServer4实现Token认证登录以及权限控制
相关知识点 不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下: 蟋蟀大神的:小菜学习编程-IdentityServer4 晓晨Master:Ide ...
- 手工搭建基于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服务也会被开放到公网并且没有做任何权限控制的,这样也会有一定的风险.所以就决定写篇文章简单介绍一个小工具. ...
随机推荐
- DBA日记:一次reboot导致的严重失误
昨天下午,一现场要添加RAC节点,db1节点正常运行,添加db2节点:在db2上做了安装的一些配置后,需要reboot, 于是直接就reboot:糟糕,这条命令错误地执行在db1上了,导致现场数据库直 ...
- IDEA 设置代码行宽度
1.在File->settings->Editor->Code Style 2.在File->settings->Editor->Code Style->XM ...
- 疑难杂症:“代理 XP”组件已作为此服务器安全配置的一部分被关闭。系统管理员可以使用 sp_configure 来启用“代理 XP”。
“代理 XP”组件已作为此服务器安全配置的一部分被关闭.系统管理员可以使用 sp_configure 来启用“代理 XP”.有关启用“代理 XP”的详细信息,请参阅 SQL Server 联机丛书中的 ...
- 【坑坑坑坑坑】fwrite没有把数据写到文件中???
原文:https://blog.csdn.net/kuaidfkuai/article/details/45918025 <unix环境高级编程>中介绍标准IO: 标准IO流操作读写普通文 ...
- python 列表之队列
列表实现队列操作(FIFO),可以使用标准库里的 collections.deque,deque是double-ended quene的缩写,双端队列的意思,它可以实现从队列头部快速增加和取出对象. ...
- 基于jQuery Ajax实现无刷新文件上传
最近因项目需求更改,需要实现选择文件后即时上传至服务器,然后提交后,加载xls表格内容到jqgrid表格中,文件上传功能实现示例: 前端jsp页面: <form id="uploadF ...
- MySQL学习_计算用户支付方式占比_20161104
计算用户支付方式占比 SELECT b.*#根据城市ID 年月排序 FROM ( SELECT a.* FROM ( #纵向合并 SELECT b1.ID,a1.城市,a1.收款方式,DATE_FOR ...
- MySQL-left join _20160928
left join 左连接 返回from 后面表的全部记录和 left join 后面表和from 后面表条件相符的全部记录 一般格式为下面,首先table A 和tableB都有两个唯一的字段标识I ...
- 关于分支和主干Merge时要注意的事项
现在我们同时在主干和分支上进行开发, 当你需要将主干上某一工程代码 Merge到分支上(或者相反)时, 不要用check out 然后全部覆盖的方法, 这样不会关联源上的任何 history, 而且需 ...
- docker学习 (二)基本概念
基本概念: Docker包括三个基本概念: 镜像(Image): 特殊的文件系统,提供容器运行时所需的程序.库.资源.配置文件.镜像不包含动态数据,内容在构建后不会被改变. 容器(Container) ...