ASP.NET Core 运行原理解剖[5]:Authentication

在现代应用程序中,认证已不再是简单的将用户凭证保存在浏览器中,而要适应多种场景,如App,WebAPI,第三方登录等等。在 ASP.NET 4.x 时代的Windows认证和Forms认证已无法满足现代化的需求,因此在ASP.NET Core 中对认证及授权进行了全新设计,使其更加灵活,可以应付各种场景。在上一章中,我们提到HttpContext中认证相关的功能放在了独立的模块中,以扩展的方式来展现,以保证HttpContext的简洁性,本章就来介绍一下 ASP.NET Core 认证系统的整个轮廓,以及它的切入点。

AuthenticationHttpContextExtensions

AuthenticationHttpContextExtensions 类是对 HttpContext 认证相关的扩展,它提供了如下扩展方法:

public static class AuthenticationHttpContextExtensions{   

 public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context, string scheme) =>context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);    public static Task ChallengeAsync(this HttpContext context, string scheme, AuthenticationProperties properties) { }    public static Task ForbidAsync(this HttpContext context, string scheme, AuthenticationProperties properties) { }    public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) {}    public static Task SignOutAsync(this HttpContext context, string scheme, AuthenticationProperties properties) { }    public static Task<string> GetTokenAsync(this HttpContext context, string scheme, string tokenName) { } }

主要包括如上6个扩展方法,其它的只是一些参数重载:

  • SignInAsync 用户登录成功后颁发一个证书(加密的用户凭证),用来标识用户的身份。

  • SignOutAsync 退出登录,如清除Coookie等。

  • AuthenticateAsync 验证在 SignInAsync 中颁发的证书,并返回一个 AuthenticateResult 对象,表示用户的身份。

  • ChallengeAsync 返回一个需要认证的标识来提示用户登录,通常会返回一个 401 状态码。

  • ForbidAsync 禁上访问,表示用户权限不足,通常会返回一个 403 状态码。

  • GetTokenAsync 用来获取 AuthenticationProperties 中保存的额外信息。

它们的实现都非常简单,与展示的第一个方法类似,从DI系统中获取到 IAuthenticationService 接口实例,然后调用其同名方法。

因此,如果我们希望使用认证服务,那么首先要注册 IAuthenticationService 的实例,ASP.NET Core 中也提供了对应注册扩展方法:

public static class AuthenticationCoreServiceCollectionExtensions{    public static IServiceCollection AddAuthenticationCore(this IServiceCollection services)    {services.TryAddScoped<IAuthenticationService, AuthenticationService>();services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>(); // Can be replaced with scoped ones that use DbContextservices.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>();services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();     
   return services;}    
   
   public static IServiceCollection AddAuthenticationCore(this IServiceCollection services, Action<AuthenticationOptions> configureOptions)    {services.AddAuthenticationCore();services.Configure(configureOptions);      
     return services;} }

如上,AddAuthenticationCore 中注册了认证系统的三大核心对象:IAuthenticationSchemeProviderIAuthenticationHandlerProvider 和 IAuthenticationService,以及一个对Claim进行转换的 IClaimsTransformation(不常用),下面就来介绍一下这三大对象。

IAuthenticationSchemeProvider

首先来解释一下 Scheme 是用来做什么的。因为在 ASP.NET Core 中可以支持各种各样的认证方式(如,cookie, bearer, oauth, openid 等等),而 Scheme 用来标识使用的是哪种认证方式,不同的认证方式其处理方式是完全不一样的,所以Scheme是非常重要的。

IAuthenticationSchemeProvider 用来提供对Scheme的注册和查询,定义如下:

public interface IAuthenticationSchemeProvider{   

 void AddScheme(AuthenticationScheme scheme);    
 Task<IEnumerable<AuthenticationScheme>> GetAllSchemesAsync();    
 Task<AuthenticationScheme> GetSchemeAsync(string name);    
 Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerSchemesAsync();  
 Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync();  
 Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync();    Task<AuthenticationScheme> GetDefaultForbidSchemeAsync();    Task<AuthenticationScheme> GetDefaultSignInSchemeAsync();  
 Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync(); }

其 AddScheme 方法,用来注册Scheme,而每一种Scheme最终体现为一个 AuthenticationScheme 类型的对象:

public class AuthenticationScheme{   

 public AuthenticationScheme(string name, string displayName, Type handlerType)    {      
   if (!typeof(IAuthenticationHandler).IsAssignableFrom(handlerType)){          
    throw new ArgumentException("handlerType must implement IAuthenticationSchemeHandler.");}...}    public string Name { get; }    public string DisplayName { get; }    public Type HandlerType { get; } }

每一个Scheme中还包含一个对应的IAuthenticationHandler类型的Handler,由它来完成具体的处理逻辑,看一下它的默认实现:

public class AuthenticationSchemeProvider : IAuthenticationSchemeProvider{   
 private IDictionary<string, AuthenticationScheme> _map = new Dictionary<string, AuthenticationScheme>(StringComparer.Ordinal);  
 
   public AuthenticationSchemeProvider(IOptions<AuthenticationOptions> options)    {_options = options.Value;    
      foreach (var builder in _options.Schemes){          
        var scheme = builder.Build();AddScheme(scheme);}}  
   
    private Task<AuthenticationScheme> GetDefaultSchemeAsync()        => _options.DefaultScheme != null? GetSchemeAsync(_options.DefaultScheme): Task.FromResult<AuthenticationScheme>(null);.... }

如上,通过一个内部的字典来保存我们所注册的Scheme,key为Scheme名称,然后提供一系列对该字典的查询。它还提供了一系列的GetDefaultXXXSchemeAsync方法,所使用的Key是通过构造函数中接收的AuthenticationOptions对象来获取的,如果未配置,则返回为null

对于 AuthenticationOptions 对象,大家可能会比较熟悉,在上面介绍的 AddAuthenticationCore 扩展方法中,也是使用该对象来配置认证系统:

public class AuthenticationOptions{  

 private readonly IList<AuthenticationSchemeBuilder> _schemes = new List<AuthenticationSchemeBuilder>();    
 
 public IEnumerable<AuthenticationSchemeBuilder> Schemes => _schemes;  
 
   public IDictionary<string, AuthenticationSchemeBuilder> SchemeMap { get; } = new Dictionary<string, AuthenticationSchemeBuilder>(StringComparer.Ordinal);  
   
    public void AddScheme(string name, Action<AuthenticationSchemeBuilder> configureBuilder)    {      
     if (SchemeMap.ContainsKey(name)){          
      throw new InvalidOperationException("Scheme already exists: " + name);}      
       var builder = new AuthenticationSchemeBuilder(name);configureBuilder(builder);_schemes.Add(builder);SchemeMap[name] = builder;}    
   
   public void AddScheme<THandler>(string name, string displayName) where THandler : IAuthenticationHandler=> AddScheme(name, b =>{b.DisplayName = displayName;b.HandlerType = typeof(THandler);});  
   
   public string DefaultScheme { get; set; }  
   
     public string DefaultAuthenticateScheme { get; set; }  
       public string DefaultSignInScheme { get; set; }  
       
        public string DefaultSignOutScheme { get; set; }
        
      public string DefaultChallengeScheme { get; set; }  
      
     public string DefaultForbidScheme { get; set; } }

该对象可以帮助我们更加方便的注册Scheme,提供泛型和 AuthenticationSchemeBuilder 两种方式配置方式。

到此,我们了解到,要想使用认证系统,必要先注册Scheme,而每一个Scheme必须指定一个Handler,否则会抛出异常,下面我们就来了解一下Handler。

IAuthenticationHandlerProvider

在 ASP.NET Core 的认证系统中,AuthenticationHandler 负责对用户凭证的验证,它定义了如下接口:

public interface IAuthenticationHandler{   

 Task InitializeAsync(AuthenticationScheme scheme, HttpContext context);    Task<AuthenticateResult> AuthenticateAsync();  
 
  Task ChallengeAsync(AuthenticationProperties properties);  
  
   Task ForbidAsync(AuthenticationProperties properties); }

AuthenticationHandler的创建是通过 IAuthenticationHandlerProvider 来完成的:

public interface IAuthenticationHandlerProvider{    Task<IAuthenticationHandler> GetHandlerAsync(HttpContext context, string authenticationScheme);
}

Provider 只定义了一个 GetHandlerAsync 方法,来获取指定的Scheme的Hander,在 ASP.NET Core 中,很多地方都使用了类似的 Provider 模式。

而HandlerProvider的实现,我们通过对上面SchemeProvider的了解,应该可以猜到一二,因为在 AuthenticationScheme 中已经包含了Hander:

public class AuthenticationHandlerProvider : IAuthenticationHandlerProvider{    

public AuthenticationHandlerProvider(IAuthenticationSchemeProvider schemes)    {Schemes = schemes;}  

 public IAuthenticationSchemeProvider Schemes { get; }  
 
  private Dictionary<string, IAuthenticationHandler> _handlerMap = new Dictionary<string, IAuthenticationHandler>(StringComparer.Ordinal);    
  
  public async Task<IAuthenticationHandler> GetHandlerAsync(HttpContext context, string authenticationScheme)    {  
       if (_handlerMap.ContainsKey(authenticationScheme)){          
        return _handlerMap[authenticationScheme];}      
         var scheme = await Schemes.GetSchemeAsync(authenticationScheme);        if (scheme == null){          
           return null;}        var handler = (context.RequestServices.GetService(scheme.HandlerType) ??ActivatorUtilities.CreateInstance(context.RequestServices, scheme.HandlerType))            as IAuthenticationHandler;        if (handler != null){            await handler.InitializeAsync(scheme, context);_handlerMap[authenticationScheme] = handler;}        return handler;} }

可以看到,AuthenticationHandlerProvider 首先使用 IAuthenticationSchemeProvider 获取到当前Scheme,然后先从DI中查找是否有此Scheme中的Handler,如果未注册到DI系统中,则使用 ActivatorUtilities 来创建其实例,并缓存到内部的 _handlerMap 字典中。

IAuthenticationService

IAuthenticationService 本质上是对 IAuthenticationSchemeProvider 和 IAuthenticationHandlerProvider 封装,用来对外提供一个统一的认证服务接口:

public interface IAuthenticationService{   

 Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme);    
 
 Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties);  
 
 Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties);  
 
 Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties);
 
 Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties); }

这5个方法中,都需要接收一个 scheme 参数,因为只有先指定你要使用的认证方式,才能知道该如何进行认证。

对于上面的前三个方法,我们知道在IAuthenticationHandler中都有对应的实现,而SignInAsyncSignOutAsync则使用了独立的定义接口:

public interface IAuthenticationSignInHandler : IAuthenticationSignOutHandler{   
  Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties); }
  
  public interface IAuthenticationSignOutHandler : IAuthenticationHandler{    Task SignOutAsync(AuthenticationProperties properties); }

SignInAsync 和 SignOutAsync 之所以使用独立的接口,是因为在现代架构中,通常会提供一个统一的认证中心,负责证书的颁发及销毁(登入和登出),而其它服务只用来验证证书,并用不到SingIn/SingOut。

而 IAuthenticationService 的默认实现 AuthenticationService 中的逻辑就非常简单了,只是调用Handler中的同名方法:

public class AuthenticationService : IAuthenticationService{  

 public IAuthenticationSchemeProvider Schemes { get; }    
 
 public IAuthenticationHandlerProvider Handlers { get; }  
 
 public IClaimsTransformation Transform { get; }  
 
 public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)    {    
     if (scheme == null){          
          var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();scheme = defaultScheme?.Name;      
           if (scheme == null){              
               throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found.");}}      
      var handler = await Handlers.GetHandlerAsync(context, scheme);
      var result = await handler.AuthenticateAsync();      
      if (result != null && result.Succeeded){          
           var transformed = await Transform.TransformAsync(result.Principal);          
          return AuthenticateResult.Success(new AuthenticationTicket(transformed, result.Properties, result.Ticket.AuthenticationScheme));}      
       return result;} }

AuthenticationService中对这5个方法的实现大致相同,首先会在我们传入的scheme为null时,来获取我们所注册的默认scheme,然后获取调用相应Handler的即可。针对 SignInAsync 和 SignOutAsync 的实现则会判断Handler是否实现了对应的接口,若未实现则抛出异常。

不过在这里还涉及到如下两个对象:

AuthenticateResult

AuthenticateResult 用来表示认证的结果:

public class AuthenticateResult{   
 public AuthenticationTicket Ticket { get; protected set; }  
      public bool Succeeded => Ticket != null;  
      public ClaimsPrincipal Principal => Ticket?.Principal;  
      public AuthenticationProperties Properties => Ticket?.Properties;                  
      public Exception Failure { get; protected set; }
      public bool None { get; protected set; }  
      
      public static AuthenticateResult Success(AuthenticationTicket ticket) => new AuthenticateResult() { Ticket = ticket };
    
      public static AuthenticateResult NoResult() => new AuthenticateResult() { None = true };
      
      public static AuthenticateResult Fail(Exception failure) => new AuthenticateResult() { Failure = failure };
      
      public static AuthenticateResult Fail(string failureMessage) => new AuthenticateResult() { Failure = new Exception(failureMessage) }; }

它主要包含一个核心属性 AuthenticationTicket

public class AuthenticationTicket{ public string AuthenticationScheme { get; private set; }  
 public ClaimsPrincipal Principal { get; private set; }  
   public AuthenticationProperties Properties { get; private set; } }

我们可以把AuthenticationTicket看成是一个经过认证后颁发的证书,

其 ClaimsPrincipal 属性我们较为熟悉,表示证书的主体,在基于声明的认证中,用来标识一个人的身份(如:姓名,邮箱等等),后续会详细介绍一下基于声明的认证。

而 AuthenticationProperties 属性用来表示证书颁发的相关信息,如颁发时间,过期时间,重定向地址等等:

public class AuthenticationProperties{  

 public IDictionary<string, string> Items { get; }  
 
   public string RedirectUri{      
    get{          
     string value;          
       return Items.TryGetValue(RedirectUriKey, out value) ? value : null;}      
        set{          
          if (value != null) Items[RedirectUriKey] = value;  
           else{            
               if (Items.ContainsKey(RedirectUriKey)) Items.Remove(RedirectUriKey);}}}... }

在上面最开始介绍的HttpContext中的 GetTokenAsync 扩展方法便是对AuthenticationProperties的扩展:

public static class AuthenticationTokenExtensions{   

 private static string TokenNamesKey = ".TokenNames";  
  private static string TokenKeyPrefix = ".Token.";    
  public static void StoreTokens(this AuthenticationProperties properties, IEnumerable<AuthenticationToken> tokens) {}  
  public static bool UpdateTokenValue(this AuthenticationProperties properties, string tokenName, string tokenValue) {}  
  public static IEnumerable<AuthenticationToken> GetTokens(this AuthenticationProperties properties) { }  
  public static string GetTokenValue(this AuthenticationProperties properties, string tokenName)    {      
   var tokenKey = TokenKeyPrefix + tokenName;  
         return properties.Items.ContainsKey(tokenKey) ? properties.Items[tokenKey] : null;}  
 public static Task<string> GetTokenAsync(this IAuthenticationService auth, HttpContext context, string tokenName)        => auth.GetTokenAsync(context, scheme: null, tokenName: tokenName);    
 public static async Task<string> GetTokenAsync(this IAuthenticationService auth, HttpContext context, string scheme, string tokenName)  
 
{  
      var result = await auth.AuthenticateAsync(context, scheme);        return result?.Properties?.GetTokenValue(tokenName);} }

如上,Token扩展只是对AuthenticationProperties中的 Items 属性进行添加和读取。

IClaimsTransformation

IClaimsTransformation 用来对由我们的应用程序传入的 ClaimsPrincipal 进行转换,它只定义了一个 Transform 方法:

public interface IClaimsTransformation{  
 Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal); }

其默认实现,不做任何处理,直接返回。它适合于全局的为 ClaimsPrincipal 添加一些预定义的声明,如添加当前时间等,然后在DI中把我们的实现注册进去即可。

Usage

下面我们演示一下 ASP.NET Core 认证系统的实际用法:

首先,我们要定义一个Handler:

public class MyHandler : IAuthenticationHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler{   

 public AuthenticationScheme Scheme { get; private set; }  
 
   protected HttpContext Context { get; private set; }  
   
    public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)    {Scheme = scheme;Context = context;        return Task.CompletedTask;}  

 public async Task<AuthenticateResult> AuthenticateAsync()    {  
       var cookie = Context.Request.Cookies["mycookie"];  
       if (string.IsNullOrEmpty(cookie)){        
   return AuthenticateResult.NoResult();}      
    return AuthenticateResult.Success(Deserialize(cookie));}    

public Task ChallengeAsync(AuthenticationProperties properties)    {Context.Response.Redirect("/login");        return Task.CompletedTask;}  

 public Task ForbidAsync(AuthenticationProperties properties)    {Context.Response.StatusCode = 403;        return Task.CompletedTask;}  

 public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)    {      
 var ticket = new AuthenticationTicket(user, properties, Scheme.Name);Context.Response.Cookies.Append("myCookie", Serialize(ticket));        return Task.CompletedTask;}    
 
 public Task SignOutAsync(AuthenticationProperties properties)    {Context.Response.Cookies.Delete("myCookie");    
     return Task.CompletedTask;} }

如上,在 SignInAsync 中将用户的Claim序列化后保存到Cookie中,在 AuthenticateAsync 中从Cookie中读取并反序列化成用户Claim。

然后在DI系统中注册我们的Handler和Scheme:

public void ConfigureServices(IServiceCollection services){services.AddAuthenticationCore(options => options.AddScheme<MyHandler>("myScheme", "demo scheme"));
}

最后,便可以通过HttpContext来调用认证系统了:

public void Configure(IApplicationBuilder app){   
 // 登录app.Map("/login", builder => builder.Use(next =>{      
  return async (context) =>{        
     var claimIdentity = new ClaimsIdentity();          
      claimIdentity.AddClaim(new Claim(ClaimTypes.Name, "jim"));            await context.SignInAsync("myScheme", new ClaimsPrincipal(claimIdentity));};}));  
       // 退出app.Map("/logout", builder => builder.Use(next =>{      
        return async (context) =>{          
         await context.SignOutAsync("myScheme");};}));    // 认证app.Use(next =>{        
         return async (context) =>{            
         var result = await context.AuthenticateAsync("myScheme");        
             if (result?.Principal != null) context.User = result.Principal;          
               await next(context);};});    // 授权app.Use(async (context, next) =>{  
 
         var user = context.User;  
        if (user?.Identity?.IsAuthenticated ?? false){      
        if (user.Identity.Name != "jim") await context.ForbidAsync("myScheme");    
        else await next();}        
        else{          
         await context.ChallengeAsync("myScheme");}});    // 访问受保护资源app.Map("/resource", builder => builder.Run(async (context) => await context.Response.WriteAsync("Hello, ASP.NET Core!"))); }

在这里完整演示了 ASP.NET Core 认证系统的基本用法,当然,在实际使用中要比这更加复杂,如安全性,易用性等方面的完善,但本质上也就这么多东西。

总结

本章基于 HttpAbstractions 对 ASP.NET Core 认证系统做了一个简单的介绍,但大多是一些抽象层次的定义,并未涉及到具体的实现。因为现实中有各种各样的场景无法预测,HttpAbstractions 提供了统一的认证规范,在我们的应用程序中,可以根据具体需求来灵活的扩展适合的认证方式。不过在 Security 提供了更加具体的实现方式,也包含了 Cookie, JwtBearer, OAuth, OpenIdConnect 等较为常用的认证实现。在下个系列会来详细介绍一下 ASP.NET Core 的认证与授权,更加偏向于实战,敬请期待!

ASP.NET Core 在GitHub上的开源地址为:https://github.com/aspnet,包含了100多个项目,ASP.NET Core 的核心是 HttpAbstractions ,其它的都是围绕着 HttpAbstractions 进行的扩展。本系列文章所涉及到的源码只包含 Hosting 和 HttpAbstractions ,它们两个已经构成了一个完整的 ASP.NET Core 运行时,不需要其它模块,就可以轻松应对一些简单的场景。当然,更多的时候我们还会使用比较熟悉的 Mvc 来大大提高开发速度和体验,后续再来介绍一下MVC的运行方式。

相关文章: 

  • .NET Core 2.0 正式发布信息汇总

  • .NET Standard 2.0 特性介绍和使用指南

  • .NET Core 2.0 的dll实时更新、https、依赖包变更问题及解决

  • .NET Core 2.0 特性介绍和使用指南

  • Entity Framework Core 2.0 新特性

  • 体验 PHP under .NET Core

  • .NET Core 2.0使用NLog

  • 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

  • 解决Visual Studio For Mac Restore失败的问题

  • ASP.NET Core 2.0 特性介绍和使用指南

  • .Net Core下通过Proxy 模式 使用 WCF

  • .NET Core 2.0 开源Office组件 NPOI

  • ASP.NET Core Razor页面 vs MVC

  • Razor Page–Asp.Net Core 2.0新功能  Razor Page介绍

  • MySql 使用 EF Core 2.0 CodeFirst、DbFirst、数据库迁移(Migration)介绍及示例

  • .NET Core 2.0迁移技巧之web.config配置文件

  • asp.net core MVC 过滤器之ExceptionFilter过滤器(一)

  • ASP.NET Core 使用Cookie验证身份

  • ASP.NET Core MVC – Tag Helpers 介绍

  • ASP.NET Core MVC – Caching Tag Helpers

  • ASP.NET Core MVC – Form Tag Helpers

  • ASP.NET Core MVC – 自定义 Tag Helpers

  • ASP.NET Core MVC – Tag Helper 组件

  • ASP.NET Core 运行原理解剖[1]:Hosting

  • ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍

  • ASP.NET Core 运行原理解剖[3]:Middleware-请求管道的构成

  • ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界

原文地址:http://www.cnblogs.com/RainingNight/p/authentication-in-asp-net-core.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

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

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

相关文章

bladex自定义分页

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年4月16日21:44:05&#xff01;今天分享一个代码段&#xff0c;个人觉得还是比较有参考性的。 后端使用框架&#xff1a;bladex前端使用技术&#xff1a;AVue功能:自定义分…

bladex中自定义分页的写法~

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是2022年4月16日21:44:05&#xff01;今天分享一个代码段&#xff0c;个人觉得还是比较有参考性的。后端使用框架&#xff1a;bladex前端使用技术&#xff1a;AVue功能:自定义分…

OpenID Connect:OAuth 2.0协议之上的简单身份层

OpenID Connect是什么&#xff1f;OpenID Connect(目前版本是1.0)是OAuth 2.0协议(可参考本人此篇&#xff1a;OAuth 2.0 / RCF6749 协议解读)之上的简单身份层&#xff0c;用 API 进行身份交互的框架&#xff0c;允许客户端根据授权服务器的认证结果最终确认用户的身份&#x…

一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系

我们知道&#xff0c;不同肤色的人外貌差别很大&#xff0c;而双胞胎的辨识很难。有意思的是Web服务器/Web容器/Web应用程序服务器/反向代理有点像四胞胎&#xff0c;在网络上经常一起出现。本文将带读者对这四个相似概念如何区分。 1.1. Web服务器概念与基本原理 1.1.1. Web服…

bladex实现单点登录

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年4月17日16:19:51 在实际开发中&#xff0c;有时候我们有这样的需求&#xff0c;即&#xff0c;一个体系中的用户是共通的&#xff0c;比如统一体系下&#…

若依实现单点登录(解析请求链接中的参数做鉴权认证)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年4月19日19:56:56 昨天写了个bladex的单点登录&#xff0c;回想起来还是比较复杂的&#xff0c;今天又收到了个在若依里面实现单点登录。具体是这样的:别的系…

Docker打包 Asp.Net Core应用,在CentOS上运行

本文主要介绍下运用docker虚拟技术打包Asp.net core应用。 Docker作为一个开源的应用容器引擎&#xff0c;近几年得到广泛的应用&#xff0c;使用Docker我们可以轻松实现应用的持续集成部署&#xff0c;一次打包&#xff0c;到处运行。 开篇借用百科上对docker的介绍。 Docker …

若依实现系统单点登录(可绕过验证码)

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年4月19日19:56:56昨天写了个bladex的单点登录&#xff0c;回想起来还是比较复杂的&#xff0c;今天又收到了个在若依里面实现单点登录。具体是这样的:别的系…

springboot解析txt文件顺便加到数据库中(nohup文件)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年4月20日13:33:23 以前是怎么都没想到&#xff0c;我需要在服务器的nohup文件中找记录&#xff0c;然后往数据库里面更新。具体因为啥不提了&#xff0c;说多…

ASP.Net Core 2.0中的Razor Page不是WebForm

随着.net core2.0的发布&#xff0c;我们可以创建2.0的web应用了。2.0中新东西的出现&#xff0c;会让我们忘记老的东西&#xff0c;他就是Razor Page。下面的这篇博客将会介绍ASP.Net Core 2.0中的Razor Page。 在ASP.Net Core 2.0新特点之一就是支持Razor Page。今天的Razor…

记录几个部署项目常用的命令

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 查询运行项目的进程 ps -aux|grep farbeat 杀死进程 kill -9 1600336进入目录 cd /www/wwwroot/farbeat/查看文件 ls将日志输出在nohup文件中的方式启动项目(注意.jar文件的名字) nohup j…

C#最佳工具集合:IDE、分析、自动化工具等

C#是企业中广泛使用的编程语言&#xff0c;特别是那些依赖微软的程序语言。如果您使用C#构建应用程序&#xff0c;则最有可能使用Visual Studio&#xff0c;并且已经寻找了一些扩展来对您的开发进行管理。但是&#xff0c;这个工具列表可能会改变您编写C#代码的方式。 C#编程的…

常用公有云接入——AZURE

一、概念 1、订阅 可以使用订阅为组织内的团队提供访问开发环境&#xff08;即测试、生产、开发、临时部署等&#xff09;和项目的权限。针对每个应用程序环境创建不同的订阅&#xff0c;并为每个订阅分配不同的服务管理员帐户&#xff0c;这是保护每个环境安全的一个好方法。…

记录几个常用部署项目的命令,以备后用!

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”查询运行项目的进程ps -aux|grep farbeat杀死进程kill -9 1600336进入目录cd /www/wwwroot/farbeat/查看文件ls将日志输出在nohup文件中的方式启动项目(注意.jar文件的名字)nohup java -…

分布式测试工具Beetle.DT的部署并进行HTTP,SQL,TCP压测

由于Beetle.DT是一个分布式压力测试工具&#xff0c;所以在使用上并不像普通工具那样安装运行这么简单&#xff1b;由于工具涉及到测试管理中心&#xff0c;节点和管理端等工具&#xff1b; 所以必须要进行相应的部署才能运行。接下来详解一下如果安装Beetle.DT并进行简单的HTT…

常用公有云接入——谷歌

一、概念 1、项目 一个账号有唯一的项目&#xff0c;所有虚拟机都在project里面建。 2、计算引擎 虚拟机资源。 二、创建方式 1、页面控制台 2、gcloud命令行 3、REST API 4、SDK 三、Java SDK 1、创建API服务凭据&#xff0c;并下载P12文件 2、Maven <dependency&…

elementui实现表格单选功能

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 需求是这样的&#xff1a;用户单击购买产品的按钮时&#xff0c;会出现一个产品的列表&#xff0c;但是呢只能买一种产品&#xff0c;暂时不可以多选。效果如下所示&#xff1a; 原来…

element-ui实现表格单选的功能

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年4月20日13:33:23需求是这样的&#xff1a;用户单击购买产品的按钮时&#xff0c;会出现一个产品的列表&#xff0c;但是呢只能买一种产品&#xff0c;暂时不…

ASP.NET Core Razor 视图组件

视图组件简介 在新的ASP.NET Core MVC中&#xff0c;视图组件类似于局部视图&#xff0c;但它们更强大。视图组件不使用模型绑定&#xff0c;仅依赖于您在调用时提供的数据。 视图组件特性&#xff1a; 呈现页面响应的某一部分而不是整个响应包括在控制器和视图之间发现的关…

三个好用的并发工具类

转载自 三个好用的并发工具类 以前的文章中&#xff0c;我们介绍了太多的底层原理技术以及新概念&#xff0c;本篇我们轻松点&#xff0c;了解下 Java 并发包下、基于这些底层原理的三个框架工具类。 它们分别是&#xff1a; 信号量 Semaphore 倒计时门栓 CountDownLatch …