asp.net权限认证:OWIN实现OAuth 2.0 之授权码模式(Authorization Code)
授权码模式定义
通过客户端的后台服务器,与“服务提供商”的认证服务器进行认证。
1、用户访问客户端,后者将前者导向认证服务器。
2、用户选择是否给予客户端授权。
3、假设用户给予授权,认证服务器首先生成一个授权码,并返回给用户,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。
4、客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
5、认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
6、Client拿着access token去访问Resource资源
授权码模式的工作流程图
图 1 (网上搜到的授权码工作流程图说明)
之前看上边的流程图,看了不下10遍,还是搞不懂,这个图真心画的不好理解!
我们一步步来,AuthorizationServer与ResourceServer还是用之前的项目
新建项目:AuthorizationCodeGrant
HomeController.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 | public ActionResult Index() { ViewBag.AccessToken = Request.Form[ "AccessToken" ] ?? "" ; ViewBag.RefreshToken = Request.Form[ "RefreshToken" ] ?? "" ; ViewBag.Action = "" ; ViewBag.ResourceResponse = "" ; var authorizationServerUri = new Uri( "http://localhost:8270/" ); var authorizationServer = new AuthorizationServerDescription { AuthorizationEndpoint = new Uri(authorizationServerUri, "OAuth/Authorize" ), TokenEndpoint = new Uri(authorizationServerUri, "OAuth/Token" ) }; // 刷新AccessToken var client = new WebServerClient(authorizationServer, "123456" , "abcdef" ); if ( string .IsNullOrEmpty(ViewBag.AccessToken)) { var authorizationState = client.ProcessUserAuthorization(Request); if (authorizationState != null ) { ViewBag.AccessToken = authorizationState.AccessToken; ViewBag.RefreshToken = authorizationState.RefreshToken; ViewBag.Action = Request.Path; } } // 授权申请 if (! string .IsNullOrEmpty(Request.Form.Get( "btnRequestAuthorize" ))) { var grantRequest = client.PrepareRequestUserAuthorization( new [] { "scopes1" , "scopes2" }); grantRequest.Send(HttpContext); Response.End(); } // 申请资源 if (! string .IsNullOrEmpty(Request.Form.Get( "btnRequestResource" ))) { var resourceServerUri = new Uri( "http://localhost:8001/" ); var resourceRequest = new HttpClient(client.CreateAuthorizingHandler(ViewBag.AccessToken)); ViewBag.ResourceResponse = resourceRequest.GetStringAsync( new Uri(resourceServerUri, "api/Values" )).Result; } return View(); } |
Index.cshtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <! DOCTYPE html> < html xmlns="http://www.w3.org/1999/xhtml"> < head > < title >Authorization Code Grant Client</ title > </ head > < body > < form id="form1" action="@ViewBag.Action" method="POST"> < div > < input id="AccessToken" name="AccessToken" value="@ViewBag.AccessToken" type="hidden" /> < input id="Authorize" name="btnRequestAuthorize" value="向认证服务器索要授权" type="submit" /> < input id="Resource" name="btnRequestResource" value="访问资源(Resource)" type="submit" /> </ div > < div >@ViewBag.ResourceResponse</ div > </ form > </ body > </ html > |
运行项目
授权过程
点击“向认证服务索要授权”,根据HomeController.cs文件的设置,页面预计会跳转到"http://localhost:8270/OAuth/Authorize"
所以我们需要在认证服务中新增处理授权码模式的处理逻辑
在项目AuthorizationServer中新增OAuthController.cs、Authorize.cshtml
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 | public class OAuthController : Controller { public ActionResult Authorize() { if (Response.StatusCode != 200) { return View( "AuthorizeError" ); } var authentication = HttpContext.GetOwinContext().Authentication; var ticket = authentication.AuthenticateAsync( "Application" ).Result; var identity = ticket != null ? ticket.Identity : null ; if (identity == null ) { authentication.Challenge( "Application" ); return new HttpUnauthorizedResult(); //用户登录凭证失效就报401错误,并且跳转至AccountController中的Login中 } ViewBag.IdentityName = identity.Name; ViewBag.Scopes = (Request.QueryString.Get( "scope" ) ?? "" ).Split( ' ' ); if (Request.HttpMethod == "POST" ) { // 点击btnGrant就确认授权,返回token等信息 if (! string .IsNullOrEmpty(Request.Form.Get( "btnGrant" ))) { identity = new ClaimsIdentity(identity.Claims, "Bearer" , identity.NameClaimType, identity.RoleClaimType); foreach ( var scope in ViewBag.Scopes) { identity.AddClaim( new Claim( "urn:oauth:scope" , scope)); } authentication.SignIn(identity); } if (! string .IsNullOrEmpty(Request.Form.Get( "btnOtherLogin" ))) { authentication.SignOut( "Application" ); authentication.Challenge( "Application" ); return new HttpUnauthorizedResult(); } } return View(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <! DOCTYPE html> < html xmlns="http://www.w3.org/1999/xhtml"> < head > < title >Authorize</ title > </ head > < body > < h1 >认证页面</ h1 > < form method="POST"> < p >登录用户:@ViewBag.IdentityName</ p > < p >第三方应用需要你给他开放以下权限</ p > < ul > @foreach (var scope in ViewBag.Scopes) { < li >@scope</ li > } </ ul > < p > < input type="submit" name="btnGrant" value="确认授权" /> < input type="submit" name="btnOtherLogin" value="以不同用户登录" /> </ p > </ form > </ body > </ html > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class AccountController : Controller { public ActionResult Login() { var authentication = HttpContext.GetOwinContext().Authentication; if (Request.HttpMethod == "POST" ) { // 默认用户登录成功 // 生产环境需要单独整合第三方登录信息 var username = Request.Form[ "username" ]; authentication.SignIn( new AuthenticationProperties { IsPersistent = true }, new ClaimsIdentity( new [] { new Claim(ClaimsIdentity.DefaultNameClaimType, username) }, "Application" )); } return View(); } public ActionResult Logout() { return View(); } } |
运行项目,成功跳转至认证登录页面
点击登录,此时url地址为:
http://localhost:8270/OAuth/Authorize?client_id=123456&redirect_uri=http%3A%2F%2Flocalhost%3A4825%2F&state=IUKeWFTR1HKi4hlzKOOPgw&scope=scopes1%20scopes2&response_type=code
7.1 client_id为客户端ID,即之前我们在AuthorizationCodeGrant项目设置的clientID
7.2 redirect_uri、state为之前登录时就确定的值
7.3 scope为用户确定授权的范围
7.4 response_type=code,即指定为授权码模式
确认授权
此时url有变化:http://localhost:4825/?code=efab38fc30c741a198b20663ec60869a36c6b25ff21f4c9986bcb9c9ae8d20eb&state=tjB9jXhNiHvIr4Ko9VhEkw
注意:这一步会会默认获取Token
点击访问资源
完全能够对上;
url中的code即认证服务返回的授权码,之后Client请求Token会用这个code来交换
这个就是授权码模式的特色的地方了
自此,整个授权码模式已经完毕了哦
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训练数据并当服务器共享给他人