net Framework OAuth2.0

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? 理论上第三方应用都应该使用【授权码模式】,但是如果你仔细看下,【简化模式】中是没有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);
        }
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

access_token

access_token不能暴露在浏览器那么该存放在哪?
重定向传回access_token会使安全保密性要求极高的访问令牌暴露在浏览器,增加访问令牌失窃风险。

在我看来,重定向携带的参数在URL上,http协议下重定向传回access_token的形式,是没有经过数据加密的,他会增加令牌失窃的风险。那么关于access_token存放在哪的问题,个人认为通过授权码以及客户端id和secret共同校验后获取的access_token,可以把access_token存放在localStorage中,localStorage虽然是永久存储,但是access_token会有一个有效期,有效期到了之后,即便access_token一直都存在但是有效期过后就无法访问到受保护资源。

》》》webstorage (sessionStorage和localStorage)
sessionStorage和localStorage区别
在这里插入图片描述
**注意: **不同浏览器无法共享localStorage或sessionStorage中的信息。
相同浏览器的不同页面间【相同域名和端口】可以共享相同的 localStorage,
但是不同页面或标签页间无法共享sessionStorage的信息。

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

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

django模型、项目、配置、模型类、数据库操作、查询、F/Q对象、字段类型、聚合函数、排序函数

模型重点 模型配置数据的增删改 增:book BookInfo() book.save() 和BookInfo.objects.create()删:book.delete() 和BookInfo.objects.get().delete()改:book.namexxx book.save() 和 BookInfo.objects.get().update(namexxx)数据的查询 基础查询F对象和Q对象关联查询 查询集Q…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 两个字符串间的最短路径(200分) - 三语言AC题解(Python/Java/Cpp)

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

海外媒体发稿:加拿大媒体宣发投放新形势-大舍传媒

1. 加拿大主要媒体 加拿大拥有众多知名的媒体机构&#xff0c;它们在各自领域内具有重要影响力。以下是加拿大一些主要媒体的 1.1 加拿大环球邮报&#xff08;The Globe And Mail&#xff09; 加拿大环球邮报是加拿大最大的全国性英文日报之一&#xff0c;成立于1874年。它以…

ASUS/华硕天选5 FX607J系列 原厂Windows11系统

安装后恢复到您开箱的体验界面&#xff0c;带原机所有驱动和软件&#xff0c;包括myasus mcafee office 奥创等。 最适合您电脑的系统&#xff0c;经厂家手调试最佳状态&#xff0c;性能与功耗直接拉满&#xff0c;体验最原汁原味的系统。 原厂系统下载网址&#xff1a;http:…

机器学习python实践——关于管道模型Pipeline和网格搜索GridSearchCV的一些个人思考

最近在利用python跟着指导书进行机器学习的实践&#xff0c;在实践中使用到了Pipeline类方法和GridSearchCV类方法&#xff0c;并且使用过程中发现了一些问题&#xff0c;所以本文主要想记录并分享一下个人对于这两种类方法的思考&#xff0c;如果有误&#xff0c;请见谅&#…

Java 实现将List按照字符串(特定规则)排序

日常开发中我们通常会遇到将一个List按照特定的规则排序&#xff0c;例如我们需要将一个List按照 “广州市”, “深圳市”, “珠海市”, “汕头市” 的顺序排序&#xff0c;我们可以使用下述方式实现。 City实体类 import lombok.AllArgsConstructor; import lombok.Data; im…

ingress相关yaml文件报错且相关资源一切正常解决方法

今天在执行ingress相关文件的时候莫名其妙报错了&#xff0c;问了别人得知了这个方法 执行ingress相关文件报错 01.yaml是我自己创建关于ingress的yaml文件 报错信息 且相关资源一切正常 解决方法 kubectl get validatingwebhookconfigurations删除ingress-nginx-admissio…

关于Mac mini 10G网口的问题

问题: 购入一个10G网口的Mac mini M2&#xff0c;将其和自己的2.5G交换机连接&#xff0c;使用共享屏幕进行远程操作的过程中出现了频率极高的卡顿&#xff0c;几乎是几秒钟卡一下&#xff0c;使用ping进行测试发现卡的时候就ping不通了。测试使用Mac mini的无线网和雷电转2.5G…

Web渗透-逻辑漏洞

一、概述 逻辑漏洞是指由于程序逻辑不严或逻辑太复杂&#xff0c;导致一些逻辑分支不能够正常处理或处理错误&#xff0c;一般出现任意密码修改&#xff08;没有旧密码验证&#xff09;,越权访问&#xff0c;密码找回&#xff0c;交易支付金额等。对常见的漏洞进行过统计&…

被 AI meme 梗图整破防了...

文章首发于公众号&#xff1a;X小鹿AI副业 大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 前一阵刚刚分享了一…

详细分析Oracle中的tnsnames.ora基本知识 以及 PLSQL如何连接(附Demo)

目录 1. tnsnames.ora2. Demo3. 实战 1. tnsnames.ora Oracle 数据库网络配置文件&#xff0c;用于配置客户端与数据库服务器之间的连接 定义网络服务名称&#xff0c;客户端可以使用这些名称连接到数据库实例 基本的路径如下&#xff1a; Windows: ORACLE_HOME\network\ad…

Docker 安装Nginx部署网站 防火墙端口 数据卷挂载

拉取镜像 docker pull nginx#不写版本号 表示最新版本查看是否拉取成功 docker images#成功 nginx latest 605c77e624dd 2 years ago 141MB mysql 8.0 3218b38490ce 2 years ago 516MB mysql latest 3218b38490ce 2 years ago 5…

算法题 — 接雨水

给定 n 给非负整数&#xff0c;表示每个宽度为 1 的柱子的高度图&#xff0c;计算按照此排列的柱子&#xff0c;下雨之后能能接到多少雨水。 输入&#xff1a;height [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0, 1, 0, 2, 1,…

capitalize()方法——字符串首字母转换为大写

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 capitalize()方法用于将字符串的首字母转换为大写&#xff0c;其他字母为小写&#xff0c;例如图1所示的效果。 图1 字符串首字母大写效果…

技术学习的奥秘与乐趣

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 在当今快速发展的科技时代&#xff0c;学习技术已经成为了许多人追求的重要目标之一。无论是为了个人发展&#…

筑算网基石 创数智未来|锐捷网络闪耀2024 MWC上海

2024年6月26日至28日&#xff0c;全球科技界瞩目的GSMA世界移动大会&#xff08;MWC 上海&#xff09;在上海新国际博览中心&#xff08;SNIEC&#xff09;盛大召开。作为行业领先的网络解决方案提供商&#xff0c;锐捷网络以“筑算网基石 创数智未来”为主题&#xff0c;带来了…

车辆轨迹预测系列 (五):Argoverse API Forecasting Tutorial代码解析

车辆轨迹预测系列 (五)&#xff1a;Argoverse API Forecasting Tutorial代码解析 文章目录 车辆轨迹预测系列 (五)&#xff1a;Argoverse API Forecasting Tutorial代码解析一、argoverse.data_loading.argoverse_forecasting_loader二、argoverse.visualization.visualize_seq…

企业级堡垒机JumpServer

文章目录 JumpServer是什么生产应用场景 Docker安装JumpServer1.Docker安装2.MySQL服务安装3.Redis服务安装4.key生成5.JumpServer安装6.登录验证 系统设置邮箱服务器用户和用户组创建系统审计员资产管理用户创建资产节点资产授权查看用户的资产监控仪表盘 命令过滤器创建命令过…

MySQL之可扩展性(八)

可扩展性 负载均衡 负载均衡的基本思路很简单:在一个服务器集群中尽可能地平均负载量。通常的做法是在服务器前端设置一个负载均衡器(一般是专门的硬件设备)。然后负载均衡器将请求的连接路由到最空闲的可用服务器。如图显示了一个典型的大型网站负载均衡设置&#xff0c;其中…

深度探讨网络安全:挑战、防御策略与实战案例

目录 ​编辑 一、引言 二、网络安全的主要挑战 恶意软件与病毒 数据泄露 分布式拒绝服务攻击&#xff08;DDoS&#xff09; 内部威胁 三、防御策略与实战案例 恶意软件防护 网络钓鱼防护 数据泄露防护 总结 一、引言 随着信息技术的迅猛发展&#xff0c;网络安全问…