net Framework OAuth2.0

news2024/7/6 19:16:40

grant_type

  1. client_credentials 客户端凭证
  2. password 密码模式 用于资源所有者密码凭据
  3. token 隐藏式 、 简化式 简化模式又称为隐式授权码模式,它是授权码模式的一个简化版本
  4. authorization_code 授权码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    A. 第三方程序向资源拥有者(用户)发送授权请求,这个过程既可以通过客户端直接向用户请求,也可以通过授权服务器作为中介来完成请求。(注:对于授权请求这个概念相当于用户登录,应用程序可以直接显示一个登录页面,也可以跳转到验证服务器的统一登录页面)
      B. 用户将授权相关信息“提交”给第三方程序,在OAuth中有4种不同的权限授予方式,每种方式需要的数据不同,如基于用户密码的授权方式就需要用户名和密码。
      C. 第三方程序将用户的授权信息提交到授权服务器,请求一个Access Token。
      D. 授权服务器验证完成用户的授权信息后,将Access Token发放到第三方程序。
      E. 第三方程序携带Access Token访问被保护的资源。
      F. 资源服务器验证Access Token有效后,将资源返回到第三方程序。
       ● Authorization Code(授权码模式):该模式的核心是客户端通过一个授权码来向授权服务器申请Access Token。是一种基于重定向的授权模式,授权服务器作为用户和第三方应用(Client)的中介,当用户访问第三方应用是,第三方应用跳转到授权服务器引导用户完成身份验证,生成Authorization Code并转交到第三方应用,以便于第三方应用根据这个授权码完成后续的Access Token获取。
      ● Implicit(简化模式):简化模式是一种简化的授权码模式,授权码模式在首次访问第三方应用时跳转到授权服务器进行身份验证返回授权码,而简化模式在跳转到授权服务器后直接返回Access Token,这种模式减少了获取Access Token的请求次数。
      ● Resource Owner Password Credentials(用户密码模式):通过资源拥有者(用户)的用户名和密码来直接获取Access Token的一种方法,这种方法要求第三方应用(Client)是高度可信任的,并且其它授权方式不可用的情况下使用。
      ● Client Credentials(客户端模式):该模式是通过第三方应用(Client)发送一个自己的凭证到授权服务器获得Access Token,这种模式的使用要求该Client已经被授权服务器管理并限制其对被保护资源的访问范围。另外这种模式下Client应该就是一个资源拥有者(用户),如微服务程序。

》》》
四个模式中,只有【客户端模式】不需要用户输入用户名和密码,因为 客户端模式,不是用户名义请求的,是客户端本身名义请求的,所以需要后台提供 client_id 和 client_secret,
根据这个两个去认证服务器【Authorization server】 获取access_token.
》》适用于没有前端的命令行应用,即在命令行下请求令牌。一般用来提供给我们完全信任的服务器端服务。

如果是第一方应用(自己开发的应用)一般我们都认为要安全一些,因为不会故意的去泄露访问resource的access token, 所以一般第一方应用我们可以使用简单的【密码模式】, 这种节省了通过code去交换access token这一步骤(实际上就是节省了一次网络请求来回),直接通过用户名,密码去获取access token。而第三方应用我们需要采用更加安全的 【授权码模式】和【简单模式】

【授权码模式】和【简单模式】、【密码模式】 都需要用户录入用户名和密码, 但【授权码模式】和【简单模式】 是认证服务器【authorization server】提供的界面录入的,【密码模式】是客户端提供的界面录入的 ,所以认证服务器提供的界面更加安全些

【简单模式】是没有授权码【code】和刷新token【refresh_code】
>>>如果有人很容易的拿到code 或 refresh token,那么就基本上可以随意随时的去访问你的resource了,因为他可以不断的通过refresh token 去刷新access token。 而为什么第三方的SPA使用的是implicit flow 而第三方的Native App却使用的是authorization code flow? 理论上第三方应用都应该使用authorization code flow,但是如果你仔细看下,implicit flow中是没有code 和 refresh token的,而SPA应用(本质上是web,需要通过浏览器的)更加容易去暴露code 和 refresh token, 所以才在第三方的SPA应用中使用了【简单模式】,而只给了access token,

》》》

安装四个包

在这里插入图片描述

客户端模式 又称简化模式

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行 授权。

适用于没有前端的命令行应用,即在命令行下请求令牌。一般用来提供给我们完全信任的服务器端服务。

在这里插入图片描述
在这里插入图片描述

》》》》 用webapi 做案例 ,新建项目 【webapi】

在这里插入图片描述
在这里插入图片描述

》》》删除自动的Global.asax, 这个文件是程序的入口,删除之后要创建一个 OWIN Startup 命名为 Startup。
在这里插入图片描述

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
using System.Web.Http;
using WebApplication3.App_Start;
using Microsoft.Owin.Cors;

[assembly: OwinStartup(typeof(WebApplication3.Startup))]

namespace WebApplication3
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {           
            HttpConfiguration configuration = new HttpConfiguration();
            //注册Swagger
            //SwaggerConfig.Register(configuration);
            //注册WebAPI
            WebApiConfig.Register(configuration);
            //注册授权服务
            AuthorizationConfig.Register(app);
            //注册Json的数据展示格式
            JsonFormatConfig.Register(configuration);
            //跨域配置
            app.UseCors(CorsOptions.AllowAll);
            app.UseWebApi(configuration);
        }
    }
}

》》》 新建类 AuthorizationConfig
在这里插入图片描述


using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebApplication3.Provider;


namespace WebApplication3.App_Start
{
    public  class AuthorizationConfig
    {
        public static void Register(Owin.IAppBuilder app)
        {
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,//允许http而非https访问
                TokenEndpointPath = new Microsoft.Owin.PathString(value: "/access_token"),//Token 请求地址
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),//Token的过期时间
                Provider = new OpenAuthorizationServerProvider(),//生成Token 配置
                RefreshTokenProvider = new OpenRefreshTokenProvider(),//生成RefreshToken的配置
            };
            app.UseOAuthAuthorizationServer(options);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }
}

》》》新建类 JsonFormatConfig

在这里插入图片描述

using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;

namespace WebApplication3.App_Start
{
    public class JsonFormatConfig
    {
        public static void Register(HttpConfiguration configuration)
        {
            configuration.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),//小驼峰命名
                DateFormatString = "yyyy-MM-dd HH:mm:ss" //日期格式化
            };
        }
    }
}

》》》新建文件夹Provider
在这里插入图片描述
》》》新建类 OpenAuthorizationServerProvider 生成 access_token
在这里插入图片描述
在这里插入图片描述

using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Security.Principal;

namespace WebApplication3.Provider
{
    /// <summary>
    /// 授权服务器配置
    /// </summary>
    public class OpenAuthorizationServerProvider:OAuthAuthorizationServerProvider
    {
        /// <summary>
        /// 验证客户端信息
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            //如果是刷新token,且不要验证。
            if (context.Parameters.Get("refresh_token") == null)
            {
                //获取clientId,ClientSecret
                string clientId, clientSecret;
                if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
                {
                    context.TryGetFormCredentials(out clientId, out clientSecret);
                }
                //对客户端Id和客户端密码进行校验  是与数据库进行比对
                if (clientId == "zen" && clientSecret == "123456")
                {
                    //通过客户端认证
                    context.Validated(clientId);
                }else{
                 context.Rejected();
                }
            }
            else
            { 
                // 通过客户端认证
                context.Validated();
            }
            return base.ValidateClientAuthentication(context);
        }
        /// <summary>
        /// 生成客户端模式Access_Token
        /// 还需要将对应的客户端信息存储在web中
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            //以下即为认证成功

            //var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            ClaimsIdentity identity = new GenericIdentity( name: context.ClientId, type: OAuthDefaults.AuthenticationType);
            //通过查数据库,得到一些用户的信息
            int userid = 13;
            string role = "管理员";
            string scope = "权限1,权限2";           
            identity.AddClaim(new Claim("userid", userid.ToString()));
            identity.AddClaim(new Claim("role", role));
            identity.AddClaim(new Claim("scope", scope));
            context.Validated(identity);
            return base.GrantClientCredentials(context);
        }
    }
}

》》》新建类 OpenRefreshTokenProvider 刷新token

在这里插入图片描述


using Microsoft.Owin.Security.Infrastructure;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication3.Provider
{
    /// <summary>
    /// 刷新Token配置
    /// </summary>
    public class OpenRefreshTokenProvider:AuthenticationTokenProvider
    {
        private static ConcurrentDictionary<string, string> _refreshTokens = new ConcurrentDictionary<string, string>();
        /// <summary>
        /// 生成Refresh_token
        /// </summary>
        /// <param name="context"></param>
        public override void Create(AuthenticationTokenCreateContext context)
        {
            context.Ticket.Properties.IssuedUtc = DateTime.UtcNow;
            context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddDays(30);

            context.SetToken(tokenValue:Guid.NewGuid().ToString(format:"N")+Guid.NewGuid().ToString(format:"N"));
            _refreshTokens[context.Token] = context.SerializeTicket();
            //base.Create(context);   
        }
        /// <summary>
        /// 使用Refresh_token 请求Access_Token
        /// </summary>
        /// <param name="context"></param>
        public override void Receive(AuthenticationTokenReceiveContext context)
        {
            string value;
            if (_refreshTokens.TryRemove(context.Token,out value))
            {
                context.DeserializeTicket(value);
            }
            base.Receive(context);
        }
    }
}

》》》 新建控制器
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Http;


namespace WebApplication3.Controllers
{
    public class HomeController : ApiController
    {
        // GET: Home
        [Authorize]
        public string Get()
        {
            var clientId = HttpContext.Current.User.Identity.Name;
            Dictionary<string,string> lst = new Dictionary<string,string>();
            foreach (Claim item in (this.User.Identity as ClaimsIdentity).Claims)
            {
                lst.Add(item.Type,item.Value);
            }
            return "我是Get方法";
        }
        // GET: Home
        public string Get(int id)
        {
            return $"这是参数为{id}的Get方法";
        }
    }
}

》》》测试 用postman
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

》》客户端凭证 走 GrantClientCredentials方法
在这里插入图片描述
在这里插入图片描述
ValidateAuthorizeRequest 》》》授权码验证
ValidateClientAuthentication 》》》客户端模式验证
ValidateClientRedirectUri
ValidateTokenRequest 》》》验证令牌请求, 简化模式、隐藏式模式

密码模式(Password Grant):

用户将用户名和密码发送给第三方应用程序,第三方应用程序直接向授权服务器请求访问令牌。

如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而授权服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

适用场景:公司搭建的授权服务器

在这里插入图片描述
(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

(C)认证服务器确认无误后,向客户端提供访问令牌。

在这里插入图片描述

在这里插入图片描述
其它都一样,修改OpenAuthorizationServerProvider 即可

using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Security.Principal;

namespace WebApplication3.Provider
{
    /// <summary>
    /// 授权服务器配置
    /// </summary>
    public class OpenAuthorizationServerProvider:OAuthAuthorizationServerProvider
    {
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            //获取用户传入的用户名和密码
            string UserName = context.UserName;
            string Password = context.Password;

            //通过查数据库,判断用户名和密码是否正确
            //以下只是一个示例,用户名必须以test开头
            if (!UserName.StartsWith("test"))
            {
                context.SetError("invalid_grant", "用户名或密码不正确");
                return;
            }

            //以下即为认证成功

            //通过查数据库,得到一些用户的信息
            int userid = 13;
            string role = "管理员";
            string scope = "权限1,权限2";

            var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            identity.AddClaim(new Claim("userid", userid.ToString()));
            identity.AddClaim(new Claim("role", role));
            identity.AddClaim(new Claim("scope", scope));

            context.Validated(identity);
        }
        /// <summary>
        /// 验证客户端信息
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
           可以验证 ClientID、ClientSecret,或不验证
            //从上下文中获取ClientID和ClientSecret
           context.TryGetFormCredentials(out string clientId, out string clientSecret);
 
	        //非法客户端
	        if (clientId == null || !clientId.StartsWith("AAA"))
	        {
	            context.SetError("invalid_clientId", "客户端没有授权");
	            return Task.FromResult<object>(null);
	        }
	    //如果不验证可以直接执行下面的 验证通过
        context.Validated();           
        }        
    }
}

在这里插入图片描述

简化模式

有些 Web 应用是纯前端应用,没有后端。必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌,这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)

简化模式不通过第三方应用程序的服务器,直接在浏览器中向授权服务器申请令牌,跳过了"授权码"这个步骤,所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。所以 不会触发 ValidateClientAuthentication

这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebApplication3.Provider;


namespace WebApplication3.App_Start
{
    public  class AuthorizationConfig
    {
        public static void Register(Owin.IAppBuilder app)
        {
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,//允许http而非https访问
                AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,//激活授权码模式
                TokenEndpointPath = new Microsoft.Owin.PathString(value: "/token"),//访问host/token获取AccessToken
                AuthorizeEndpointPath = new Microsoft.Owin.PathString("/auth"),//访问host/auth获取授权码
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),//AccessToken在30分钟后过期
                Provider = new OpenAuthorizationServerProvider(),//AccessToken的提供类
                // 简化模式  省略下面代码   简化模式又称为隐式授权码模式,它是授权码模式的一个简化版本
                //AuthorizationCodeProvider = new OpenAuthorizationCodeProvider(),//授权码的提供类 
                RefreshTokenProvider = new OpenRefreshTokenProvider(),//生成RefreshToken的配置

            };
            app.UseOAuthAuthorizationServer(options);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Security.Principal;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;

namespace WebApplication3.Provider
{
    /// <summary>
    /// 授权服务器配置
    /// </summary>
    public class OpenAuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        /// <summary>
        /// 验证重定向URI是否合法
        /// 授权码模式、简化模式 都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
        {
            string url = context.RedirectUri;
            context.Validated(context.RedirectUri);
        }
        /// <summary>
        /// 验证请求信息是否合法
        /// 授权码模式、简化模式 都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context)
        {
            if (context.AuthorizeRequest.ClientId.StartsWith("zen"))
            {
                context.Validated();
            }
            else
            {
                context.Rejected();
            }
        }
        /// <summary>
        /// 完成认证,跳转到重定向URI
        /// 授权码模式、简化模式 都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
        {
            var identity = new ClaimsIdentity("Bearer");
            context.OwinContext.Authentication.SignIn(identity);
            context.RequestCompleted();
        }  
    }
}

》》访问
在这里插入图片描述
》》直接跳转 access_token 是通过锚链接的
在这里插入图片描述
在这里插入图片描述

授权码模式 :

一、是获取授权码,
二、是获取AccessToken

在获取授权码时,我们需要请求host/auth这个地址,输入的参数有以下要求:

(1)grant_type,必须为authorization_code。

(2)response_type,必须为code。

(3)client_id,客户端ID。

(4)redirect_uri,重定向地址,如为http://abc.com/,
则请求授权码完成后,将会重定向到:http://abc.com/code=[授权码]。

(5)scope,授权范围,可选。

(6)state,客户端状态,可选。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

》》》Startup 同上
》》》JsonFormatConfig 同上
》》》api控制器同上
》》》OpenRefreshTokenProvider 刷新token 同上
》》》 AuthorizationConfig 类

在这里插入图片描述


using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebApplication3.Provider;


namespace WebApplication3.App_Start
{
    public  class AuthorizationConfig
    {
        public static void Register(Owin.IAppBuilder app)
        {
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,//允许http而非https访问
                AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,//激活授权码模式
                TokenEndpointPath = new Microsoft.Owin.PathString(value: "/token"),//访问host/token获取AccessToken
                AuthorizeEndpointPath = new Microsoft.Owin.PathString("/auth"),//访问host/auth获取授权码
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),//AccessToken在30分钟后过期
                Provider = new OpenAuthorizationServerProvider(),//AccessToken的提供类
                // 简化模式  省略下面代码   简化模式又称为隐式授权码模式,它是授权码模式的一个简化版本
                AuthorizationCodeProvider = new OpenAuthorizationCodeProvider(),//授权码的提供类 
                RefreshTokenProvider = new OpenRefreshTokenProvider(),//生成RefreshToken的配置

            };
            app.UseOAuthAuthorizationServer(options);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }
}

》》》OpenAuthorizationServerProvider

using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Security.Principal;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;

namespace WebApplication3.Provider
{
    /// <summary>
    /// 授权服务器配置
    /// </summary>
    public class OpenAuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        /// <summary>
        /// 验证重定向URI是否合法
        /// 授权码模式、简化模式 都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override  Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
        {
            string url = context.RedirectUri;
            context.Validated(context.RedirectUri);
            return base.ValidateClientRedirectUri(context);
        }
        /// <summary>
        /// 验证请求信息是否合法
        /// 授权码模式、简化模式 都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context)
        {
            if (context.AuthorizeRequest.ClientId.StartsWith("zen"))
            {
                context.Validated();
            }
            else
            {
                context.Rejected();
            }
        }
        /// <summary>
        /// 完成认证,跳转到重定向URI
        /// 授权码模式、简化模式 都会触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
        {

            //授权码模式
            var redirectUri = context.Request.Query["redirect_uri"];
            var clientId = context.Request.Query["client_id"];
            var identity = new ClaimsIdentity(new GenericIdentity(
                clientId, OAuthDefaults.AuthenticationType));        
            var authorizeCodeContext = new AuthenticationTokenCreateContext(
                context.OwinContext,
                context.Options.AuthorizationCodeFormat,
                new AuthenticationTicket(
                    identity,
                    new AuthenticationProperties(new Dictionary<string, string>
                    {
                        {"client_id", clientId},
                        {"redirect_uri", redirectUri}
                    })
                    {
                        IssuedUtc = DateTimeOffset.UtcNow,
                        ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AccessTokenExpireTimeSpan)
                    }));

            await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);

            context.Response.Write(Uri.EscapeDataString(authorizeCodeContext.Token));//为了测试方便,直接打印出code
            //正常使用时是把code加在重定向网址后面
            //context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));

            context.RequestCompleted();
        }
        /// <summary>
        /// 验证客户端
        //
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override  Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            string cd = context.ClientId;
            string clientId, clientSecret;
            context.TryGetFormCredentials(out clientId, out clientSecret);
            if (!clientId.StartsWith("zen"))
            {
                context.SetError("invalid_client", "未授权的客户端");
                return Task.FromResult<object>(null); ;
            }
            context.Validated();
            return Task.FromResult<object>(null);


        }
        /// <summary>
        /// 生成客户端模式Access_Token
        /// 还需要将对应的客户端信息存储在web中
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            //以下即为认证成功

           
            return base.GrantClientCredentials(context);
        }
        public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            // 以下即为认证成功

            //var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            ClaimsIdentity identity = new GenericIdentity(name: context.ClientId, type: OAuthDefaults.AuthenticationType);
            //通过查数据库,得到一些用户的信息
            int userid = 13;
            string role = "管理员";
            string scope = "权限1,权限2";
            identity.AddClaim(new Claim("userid", userid.ToString()));
            identity.AddClaim(new Claim("role", role));
            identity.AddClaim(new Claim("scope", scope));
            context.Validated(identity);
            return base.GrantResourceOwnerCredentials(context);
        }
        public override async Task ValidateTokenRequest(OAuthValidateTokenRequestContext context)
        {
            if (context.TokenRequest.IsAuthorizationCodeGrantType)
            {
                context.Validated();
            }
            else
            {
                context.Rejected();
            }

        }

    }
}

》》》 OpenAuthorizationCodeProvider

using Microsoft.Owin.Security.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace WebApplication3.Provider
{
    public class OpenAuthorizationCodeProvider : IAuthenticationTokenProvider
    {
        private Dictionary<string, string> codes = new Dictionary<string, string>();

        public void Create(AuthenticationTokenCreateContext context)
        {
            string new_code = Guid.NewGuid().ToString("n");
            context.SetToken(new_code);
            //context.SerializeTicket() 生成token
            codes.Add(new_code, context.SerializeTicket());
        }

        public Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            Create(context);
            return Task.FromResult<object>(null);
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            string code = context.Token;
            if (codes.ContainsKey(code))
            {
                string value = codes[code];
                codes.Remove(code);
                context.DeserializeTicket(value);
            }
        }

        public Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            Receive(context);
            return Task.FromResult<object>(null);
        }
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1871595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何获得更高质量的回答-chatgpt

在与技术助手如ChatGPT进行交互时&#xff0c;提问的方式直接影响到你获得的答案质量。以下是几个关键的提问技巧&#xff0c;可以帮助你在与ChatGPT的互动中获得更有效的回答&#xff1a; 1. 清晰明了的问题 技巧&#xff1a;确保问题清晰明了&#xff0c;避免含糊不清或模糊的…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 特殊加密算法(200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

一键智控,舒适无限:网关在风机盘管智能温控中的应用

风机盘管智能控制系统采用钡铼技术系列无线网关&#xff0c;搭配各类风机设备及传感器组成无线物联中央空调室内机管理系统&#xff0c;实现整个办公楼的空调环境智能化管理。在建筑舒适度的前提下&#xff0c;降低能耗&#xff0c;避免能源浪费。 网关通信接口采用无线传输的…

vscode刷LeetCode算法题环境配置

首先&#xff0c;下载nodejs 在vscode中安装LeetCode插件 安装好进行配置 选择leetcode-cn 填上刚才下载node.exe的路径 完成之后重启一下vscode 重启之后登陆LeetCode 完成之后就可以看到题目了 点击 code now 就可以开始刷题了

Flutter循序渐进==>第一个界面

导言 const MyApp({Key? key}) : super(key: key); const: 这个关键字表示这是一个编译时常量构造函数。当一个类使用 const 构造函数初始化时&#xff0c;它的所有字段都将被设置为编译时常量&#xff0c;并且该对象将在编译时就被创建出来。这对于状态不变&#xff08;immu…

基于单片机和LabVIEW 的远程矿井水位监控系统设计

摘要 &#xff1a; 针 对 现 有 矿 井 水 位 监 控 系 统 存 在 结 构 复 杂 和 不 能 远 程 监 控 的 问 题 &#xff0c; 设计了基于单片机和&#xff2c;&#xff41;&#xff42;&#xff36;&#xff29;&#xff25;&#xff37; 的远程矿井水位监控系统 &#xff0c; 详…

python-(opencv)视频转glf

文章目录 前言python-(opencv)视频转glf1. 下载 opencv-python2. cv2&#xff08;OpenCV&#xff09;和imageio的区别3. demo源码 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说…

uView 2.0:uni-app生态的利剑出鞘,引领UI框架新纪元

引言 随着移动互联网的快速发展&#xff0c;跨平台应用开发成为了开发者们关注的焦点。uni-app&#xff0c;一个基于Vue.js的跨平台应用开发框架&#xff0c;因其高效、易用的特性而广受欢迎。在uni-app的生态系统中&#xff0c;UI框架的选择对于开发者而言至关重要。今天&…

2024上海CDIE 参展预告 | 一站式云原生数字化平台已成趋势

为什么企业需要进行数字化转型&#xff1f;大家都在讨论的数字化转型面临哪些困境&#xff1f;2024.6.25-26 CDIE数字化创新博览会现场&#xff0c;展位【A18】&#xff0c;期待与您相遇&#xff0c;共同探讨企业如何利用数字化技术驱动业务增长。 一、展会介绍——CDIE数字化…

C语言 | Leetcode C语言题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; int rangeBitwiseAnd(int m, int n) {while (m < n) {// 抹去最右边的 1n & (n - 1);}return n; }

【Linux操作系统】进程地址空间与动态库加载

当系统执行一个依赖动态库的可执行程序时&#xff0c;系统不仅要将该可执行程序加载到内存中还要由加载器将动态库加载到内存中&#xff08;静态库没有&#xff09;&#xff0c;因此必须要让加载器知道该动态库的名称&#xff0c;系统会默认在/lib64路径下查找&#xff0c;解决…

Java将list数组中重复的对象进行去重

/*** 数组去重*/ public class ArrayDistinct {public static void main(String[] args) {ArrayList<Object> list new ArrayList<>();JSONObject jsonObject1 new JSONObject();jsonObject1.put("name","张三");jsonObject1.put("age&…

Vite: 关于Rollup打包

概述 Rollup 是一款基于 ES Module 模块规范实现的 JavaScript 打包工具&#xff0c;在前端社区中赫赫有名&#xff0c;同时也在 Vite 的架构体系中发挥着重要作用不仅是 Vite 生产环境下的打包工具&#xff0c;其插件机制也被 Vite 所兼容&#xff0c;可以说是 Vite 的构建基…

kubekey 安装高可用 kubernetes 集群

1. 准备环境 1.1 机器准备 4 台机器&#xff0c;操作系统&#xff1a;Ubuntu 24.04/RHEL8/CentOS9 10.111.3.53 master1 10.111.3.54 master2 10.111.3.55 master3 10.111.3.57 node41.2 安装依赖和配置 所有节点都需要执行&#xff1a; Ubuntu: apt-get install -y soca…

JeeSite中的数据库表动态建模与管理模块(DBM)

一、引言 在现代软件开发中&#xff0c;数据库作为系统数据存储和管理的核心&#xff0c;其设计和维护的灵活性、可扩展性对于系统的长期稳定运行至关重要。JeeSite作为一款流行的企业级快速开发平台&#xff0c;其数据库表动态管理模块&#xff08;DBM&#xff09;提供了强大…

UWB:DS-TWR( Double-sided two-way ranging)双边测距公式推导:为啥是乘法?

UWB DS-TWR&#xff08; Double-sided two-way ranging&#xff09;双边测距为啥是乘法&#xff1f;&#xff1f; 公式&#xff1a; 我们先看单边 Single-Sided Two-Way Ranging (SS-TWR) 单边很好理解。 symmetric double-sided TWR (SDS-TWR)对称的双边测距 再看双边 Trou…

相机系列——从相机畸变到托勒密地图

by 木一 标签&#xff1a;#相机畸变 #畸变纠正 #鱼眼相机 #折射定律 #托勒密地图 引言 前文[1][2]我们介绍了针孔相机模型&#xff0c;以及针孔相机模型的相机标定过程&#xff0c;但针孔相机模型是对相机成像最简单的描述&#xff0c;实际的相机成像过程要远复杂很多。 首先…

C++ | Leetcode C++题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; class Solution { public:int rangeBitwiseAnd(int m, int n) {while (m < n) {// 抹去最右边的 1n n & (n - 1);}return n;} };

Flutter循序渐进==>Dart之类型、控制流和循环

导言 磨刀不误砍柴工&#xff0c;想搞好Flutter&#xff0c;先学好Flutter&#xff0c;还是本着我学Python的方法&#xff0c;先从数据类型、控制流和循环开始&#xff0c;这是每一种编程语言必用的。编程语言是相通的&#xff0c;基本精通一种后&#xff0c;学其它的就变得很…

macos Automator自动操作 app, 创建自定义 应用程序 app 的方法

mac内置的这个 自动操作 automator 应用程序&#xff0c;可以帮助我们做很多的重复的工作&#xff0c;可以创建工作流&#xff0c; 可以录制并回放操作&#xff0c; 还可以帮助我们创建自定的应用程序&#xff0c;下面我们就以创建一个自定义启动参数的chrome.app为例&#xff…