asp.net权限认证:OWIN实现OAuth 2.0 之客户端模式(Client Credential)
客户端模式定义
客户端使用自己的名义,而不是用户的名义,向“服务提供商” 进行认证。
如何理解这句话? 乍一看,定义有点拗口,刚接触的童鞋可能完全不知所云。
没关系,我们先把他的工作流程图画出来,如下:
据上图,可以得出一个大概的结论
1、用户(User)通过客户端(Client)访问受限资源(Resource)
2、因为资源受限,所以需要授权;而这个授权是Client与Authentication之间完成的,可以说跟User没有什么关系
3、根据2得出,Resource与User没有关联关系,即User不是这个Resource的Owner(所有者)
既然是这样,那大概可以推出这种认证的适用范围。
第一,肯定不能用作登录认证!因为登录认证后需要得到用户的一些基本信息,如昵称,头像之类,这些信息是属于User的;
第二,适用于一些对于权限要求不强的资源认证,比如:仅用于区分用户是否登录,排除匿名用户获取资源
新建一个资源项目:ResourceServer
引用owin:install-package Microsoft.Owin -Version 2.1.0
新增Startup.cs
1 2 3 4 5 6 7 8 9 10 11 | [assembly: OwinStartup( typeof (ResourceServer.Startup))] namespace ResourceServer { public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); } } } |
新增Startup.Auth.cs
1 2 3 4 5 6 7 8 9 10 | namespace ResourceServer { public partial class Startup { public void ConfigureAuth(IAppBuilder app) {<br> // 这句是资源服务器认证token的关键,认证逻辑在里边封装好了,我们看不到 app.UseOAuthBearerAuthentication( new Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationOptions()); } } } |
新增ValuesController.cs
1 2 3 4 5 6 7 8 9 10 11 | namespace ResourceServer.Controllers { [Authorize] public class ValuesController : ApiController { public string Get() { return "lanxiaoke" ; } } } |
新建认证服务项目
修改Startup.Auth.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | public partial class Startup { public void ConfigureAuth(IAppBuilder app) { // Setup Authorization Server app.UseOAuthAuthorizationServer( new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString( "/OAuth/Token" ), ApplicationCanDisplayErrors = true , #if DEBUG AllowInsecureHttp = true , #endif // Authorization server provider which controls the lifecycle of Authorization Server Provider = new OAuthAuthorizationServerProvider { OnValidateClientAuthentication = ValidateClientAuthentication, OnGrantClientCredentials = GrantClientCredetails }, // Authorization code provider which creates and receives authorization code AuthorizationCodeProvider = new AuthenticationTokenProvider { OnCreate = CreateAuthenticationCode, OnReceive = ReceiveAuthenticationCode, }, // Refresh token provider which creates and receives referesh token RefreshTokenProvider = new AuthenticationTokenProvider { OnCreate = CreateRefreshToken, OnReceive = ReceiveRefreshToken, } }); } private Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { string clientId; string clientSecret; if (context.TryGetBasicCredentials( out clientId, out clientSecret) || context.TryGetFormCredentials( out clientId, out clientSecret)) { if (clientId == "123456" && clientSecret == "abcdef" ) { context.Validated(); } } return Task.FromResult(0); } private Task GrantClientCredetails(OAuthGrantClientCredentialsContext context) { var identity = new ClaimsIdentity( new GenericIdentity(context.ClientId, OAuthDefaults.AuthenticationType), context.Scope.Select(x => new Claim( "urn:oauth:scope" , x))); context.Validated(identity); return Task.FromResult(0); } private readonly ConcurrentDictionary< string , string > _authenticationCodes = new ConcurrentDictionary< string , string >(StringComparer.Ordinal); private void CreateAuthenticationCode(AuthenticationTokenCreateContext context) { context.SetToken(Guid.NewGuid().ToString( "n" ) + Guid.NewGuid().ToString( "n" )); _authenticationCodes[context.Token] = context.SerializeTicket(); } private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context) { string value; if (_authenticationCodes.TryRemove(context.Token, out value)) { context.DeserializeTicket(value); } } private void CreateRefreshToken(AuthenticationTokenCreateContext context) { context.SetToken(context.SerializeTicket()); } private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context) { context.DeserializeTicket(context.Token); } } |
自此,认证服务项目算是建好了,因为对于客户端模式,认证服务器只需要返回token
新增Client项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | static void Main( string [] args) { var authorizationServerUri = new Uri( "http://localhost:8270/" ); var authorizationServerDescription = new AuthorizationServerDescription { TokenEndpoint = new Uri(authorizationServerUri, "OAuth/Token" ) }; var client = new WebServerClient(authorizationServerDescription, "123456" , "abcdef" ); var state = client.GetClientAccessToken( new [] { "scopes1" , "scopes2" }); var token = state.AccessToken; Console.WriteLine( "Token: {0}" , token); var resourceServerUri = new Uri( "http://localhost:8001/" ); var httpClient = new HttpClient(client.CreateAuthorizingHandler(token)); var values = httpClient.GetStringAsync( new Uri(resourceServerUri, "api/Values" )).Result; Console.WriteLine( "Result: {0}" , values); Console.ReadKey(); } |
OK,Client环境搭好了,我们来运行下试试
认证成功!
asp.net权限认证系列
- asp.net权限认证:Forms认证
- asp.net权限认证:HTTP基本认证(http basic)
- asp.net权限认证:Windows认证
- asp.net权限认证:摘要认证(digest authentication)
- asp.net权限认证:OWIN实现OAuth 2.0 之客户端模式(Client Credential)
- asp.net权限认证:OWIN实现OAuth 2.0 之密码模式(Resource Owner Password Credential)
- asp.net权限认证:OWIN实现OAuth 2.0 之授权码模式(Authorization Code)
- asp.net权限认证:OWIN实现OAuth 2.0 之简化模式(Implicit)
分类:
权限认证
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人