.NET Core OAuth IdentityServer4 AllowAnonymous Policy 白名单 .NET 5 IdentityServer4 4.X版本 授权策略

在 ASP.NET Core 中配置证书身份验证 (TLS,HTTPS 证书)
ASP.NET Core 中基于策略的授权  
IdentityServer4 官网
jwt.io

.NET 5 IdentityServer4 4.X版本配置

1、在.NET Core 3.X 配置[AllowAnonymous]
2、配置白名单:whiteController,whiteAction
3、Policy 策略授权  ASP.NET Core 中基于策略的授权

1、Controller
NuGet 程序包:Microsoft.AspNetCore.Authorization

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace WebAPI.Controllers
{
    [ApiVersion("1.0")]
    [Route("v{version:apiVersion}/agencys")]
    public class TestController : ApiBaseController
    {
        private readonly IAgencyRepository _agencyRepo;
        private readonly IMapper _mapper;

        public TestController(IAgencyRepository agencyRepo, IMapper mapper)
        {
            _agencyRepo = agencyRepo;
            _mapper = mapper;
        }

        [AllowAnonymous]
        [HttpGet]
        public QueryAgencyResponse GetPageList([FromQuery] QueryAgencyRequest request)
        {
            PagingDto<AgencyDto> result = _agencyRepo.GetPageList(request);
            return new QueryAgencyResponse { data = result };
        }

        [Authorize(Roles = "admin,customer")]
        [Authorize(Policy = "super_admin")]
        [Authorize(Policy = "require_claim_user_name")]
        [HttpGet("page_async")]
        public async Task<QueryAgencyResponse> GetPageListAsync([FromQuery] QueryAgencyRequest request)
        {
            PagingDto<AgencyDto> result = await _agencyRepo.GetPageListAsync(request);
            return new QueryAgencyResponse { data = result };
        }
    }
}

2、Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Threading.Tasks;
using Autofac;
using AutoMapper;
using IdentityModel.AspNetCore.OAuth2Introspection;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Nuclein.WebAPI
{
  public class Startup
  {
    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
      Configuration = configuration;

      var builder = new ConfigurationBuilder()
       .SetBasePath(env.ContentRootPath)
       .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
       .AddEnvironmentVariables();
      Configuration = builder.Build();
    }

    public IConfiguration Configuration { get; }

    readonly string AllowSpecificOrigins = "AllowSpecificOrigins";

    public void ConfigureContainer(ContainerBuilder containerBuilder)
    {
      containerBuilder.RegisterModule<AutofacModule>();
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddDbContext<NucleinDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

      #region 认证
      services.AddAuthentication(config =>
      {
        config.DefaultScheme = "Bearer";
      })
      .AddIdentityServerAuthentication(options =>
      {
        options.Authority = Configuration["IdentityAuthentication:Authority"];
        options.ApiName = Configuration["IdentityAuthentication:ApiName"];
        options.ApiSecret = Configuration["IdentityAuthentication:ApiSecret"];
        options.RequireHttpsMetadata = true;
        //options.EnableCaching = true;
        //options.CacheDuration = TimeSpan.FromMinutes(10);
        options.OAuth2IntrospectionEvents = new OAuth2IntrospectionEvents
        {
          OnAuthenticationFailed = context =>
          {
            // 身份验证失败
            context.Response.ContentType = "application/json";
            context.Response.WriteAsync(JsonConvert.SerializeObject(new { code = (int)EnumCode.UnAuthorized, message = "Unauthorized" }));
            return Task.CompletedTask;
          }
        };
        options.TokenRetriever = request =>
        {
          // 令牌检索器,获取token值
          var token = TokenRetrieval.FromAuthorizationHeader()(request);
          if (string.IsNullOrWhiteSpace(token))
            token = TokenRetrieval.FromQueryString()(request);
          return token;
        };
      });
      #endregion

      #region 授权策略
      services.AddAuthorization(options =>
      {
          //基于角色组策略
          options.AddPolicy("require_claim_role", policy => policy.RequireRole("admin", "system"));
          //基于用户名策略
          options.AddPolicy("require_claim_user_name", policy => policy.RequireUserName("admin"));
          //基于ClaimType策略
          options.AddPolicy("require_claim_type", policy => policy.RequireClaim(ClaimTypes.Country, "中国"));
          //自定义值策略
          options.AddPolicy("super_admin", policy => policy.RequireClaim("super_admin"));
      });
      #endregion

      services.AddControllers(options =>
      {
        options.Filters.Add<AuthorizeAttribute>();
        options.Filters.Add<ValidateModelAttribute>();
        options.UseCentralRoutePrefix(new RouteAttribute($"api"));
        options.MaxModelValidationErrors = 50;
      })
      .ConfigureApiBehaviorOptions(options =>
      {
        options.InvalidModelStateResponseFactory = context =>
        {
          var result = new BadRequestObjectResult(context.ModelState);
          result.ContentTypes.Add(MediaTypeNames.Application.Json);
          result.ContentTypes.Add(MediaTypeNames.Application.Xml);
          return result;
        };
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[404].Link = "https://httpstatuses.com/404";
      })
      .AddNewtonsoftJson(options =>
      {
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        //options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
        options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm";
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
      });

      services.AddApiVersioning(options =>
      {
        options.ReportApiVersions = true;
        options.AssumeDefaultVersionWhenUnspecified = true;
        options.DefaultApiVersion = new ApiVersion(0, 1);
      });

      #region Swagger
      services.AddSwaggerGen(c =>
      {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });

        #region 添加header参数
        var securityScheme = new OpenApiSecurityScheme()
        {
          Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
          Name = "Authorization",
          In = ParameterLocation.Header,
          Type = SecuritySchemeType.Http,
          Scheme = "bearer",
          BearerFormat = "JWT"
        };

        var securityRequirement = new OpenApiSecurityRequirement
        {
          {
            new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "bearerAuth"}},
            new string[] {}
          }
        };
        c.AddSecurityDefinition("bearerAuth", securityScheme);
        c.AddSecurityRequirement(securityRequirement);
        #endregion
      });
      #endregion

      #region 跨域访问
      var urls = Configuration["AppSettings:Cores"].Split(',');
      services.AddCors(options =>
      {
        options.AddPolicy(AllowSpecificOrigins, builder =>
        {
          builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
          //builder.AllowAnyMethod().AllowAnyHeader().AllowCredentials();
        });
      });
      #endregion

      #region AutoMapper
      services.AddAutoMapper(typeof(AutoMapperInit));
      #endregion
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }
      else
      {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
      }

      app.UseHttpsRedirection();

      app.UseStaticFiles();

      app.UseStatusCodePages();
      app.UseCors(AllowSpecificOrigins);
      app.UseSwagger();
      app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });

      app.UseRouting();

      app.UseAuthentication();
      app.UseAuthorization();

      app.UseEndpoints(endpoints =>
      {
        endpoints.MapControllers();
      });

      app.UseApiVersioning();
    }
  }
}

3、AuthorizeFilter 过滤器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Nuclein.CoreLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace Nuclein.WebAPI
{
    public class AuthorizeAttribute : AuthorizeFilter
    {
        private static AuthorizationPolicy _policy_ = new AuthorizationPolicy(new[] { new DenyAnonymousAuthorizationRequirement() }, new string[] { });

        public AuthorizeAttribute() : base(_policy_) { }

        /// <summary>
        ///  请求验证,当前验证部分不要抛出异常,ExceptionFilter不会处理
        /// </summary>
        /// <param name="context">请求内容信息</param>
        public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            #region AllowAnonymous【OK】
            //var endpoint = context.HttpContext.Features.Get<IEndpointFeature>()?.Endpoint;
            //if (endpoint != null && endpoint.Metadata.GetMetadata<AllowAnonymousAttribute>() != null)
            //    return;
            #endregion

            #region AllowAnonymous【OK】
            //var action = context.ActionDescriptor;
            //if (action.EndpointMetadata.Any(p => p is AllowAnonymousAttribute))
            //    return;
            #endregion

            #region AllowAnonymous【OK】
            var action = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;
            var allowanyone = cad.ControllerTypeInfo.GetCustomAttributes(typeof(IAllowAnonymous), true).Any()
            || action.MethodInfo.GetCustomAttributes(typeof(IAllowAnonymous), true).Any();
            if (allowanyone)
                return;
            #endregion

            List<string> whiteController = StringPlus.StringToListString(ConfigManager.Configuration["AppSettings:whiteController"]);
            List<string> whiteAction = StringPlus.StringToListString(ConfigManager.Configuration["AppSettings:whiteAction"]);

            #region Header
            var request = context.HttpContext.Request;
            var headers = request.Headers;
            #endregion

            #region url地址
            var originalUrl = request.Path.Value;
            string controllerName = string.Empty;
            string actionName = string.Empty;
            var list = originalUrl.Split("/").Where(x => !string.IsNullOrEmpty(x) && !x.Contains("v") && !x.Contains("api")).ToArray();
            if (list.Length > 0)
            {
                controllerName = list[0].ToString().Trim();
            }
            if (list.Length > 1)
            {
                actionName = list[1].ToString().Trim();
            }
            #endregion

            if (whiteController.Contains(controllerName))
                return;
            if (controllerName.ToLower() == "passport" && (actionName.ToLower() == "login" || actionName.ToLower() == "refresh_token"))
                return;
 
            if (!context.HttpContext.User.Identity.IsAuthenticated || context.Filters.Any(item => item is IAllowAnonymousFilter))
            {
                context.Result = new JsonResult(new { code = "401", msg = "Unauthorized" });
                return;
            }
            if (context.HttpContext.User.Identity.IsAuthenticated)
            {
                var claimIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;
                Claim userClaim = claimIdentity.Claims.Where(x => x.Type.Contains("user_code")).FirstOrDefault();
                if (IsHaveAllow(context.Filters))
                {
                    context.Result = new JsonResult(new { code = "401", msg = "Unauthorized" });
                    return;
                }
            }
            //if (context.HttpContext.User.Identity.Name != "admin")
            //{
            //    //未通过验证则跳转到无权限提示页
            //    RedirectToActionResult content = new RedirectToActionResult("NoAuth", "Exception", null);
            //    context.Result = content;
            //}
            await base.OnAuthorizationAsync(context);
        }

        /// <summary>
        /// 判断是否不需要权限
        /// </summary>
        /// <param name="filers"></param>
        /// <returns></returns>
        public static bool IsHaveAllow(IList<IFilterMetadata> filers)
        {
            for (int i = 0; i < filers.Count; i++)
            {
                if (filers[i] is IAllowAnonymousFilter)
                {
                    return true;
                }
            }
            return false;
        }
    }
}

4、.NET 5 IdentityServer4 4.X版本配置【\AuthService\Security\IdentityConfig.cs】

using AuthService.CoreLibrary;
using IdentityServer4.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AuthService.Security
{
  public class IdentityConfig
  {
    public static IEnumerable<ApiResource> GetResources()
    {
      return new List<ApiResource>
      {
        new ApiResource(ConfigManager.Configuration["IdentityAuthentication:Scope"],ConfigManager.Configuration["IdentityAuthentication:ClientName"])
        {
          #region ids4 4.X 新特性
          Scopes = { "Asset",ConfigManager.Configuration["IdentityAuthentication:Scope"]},
          #endregion
          ApiSecrets = { new Secret(ConfigManager.Configuration["IdentityAuthentication:Secret"].Sha256()) }
        }
      };
    }

    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
      return new IdentityResource[]
      {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
      };
    }

    /// <summary>
    /// ids4 4.X 新特性
    /// </summary>
    /// <returns></returns>
    public static IEnumerable<ApiScope> GetScopes()
    {
      return new ApiScope[]
      {
        new ApiScope("Asset"),
        new ApiScope(ConfigManager.Configuration["IdentityAuthentication:Scope"]),
      };
    }

    /// <summary>
    /// ids4 4.X 新特性
    /// </summary>
    public static IEnumerable<ApiScope> ApiScopes =>
      new ApiScope[]
      {
        new ApiScope("Asset"),
        new ApiScope(ConfigManager.Configuration["IdentityAuthentication:Scope"]),
      };
  }
}

5、.NET 5 IdentityServer4 4.X版本配置【\AuthService\Startup.cs】

using AuthService.Filters;
using IdentityServer4.Configuration;
using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;

namespace AuthService
{
  public class Startup
  {
    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddIdentityServer(options => { })
        .AddDeveloperSigningCredential()
        .AddInMemoryClients(Security.Clients.GetClients())
        .AddInMemoryIdentityResources(Security.IdentityConfig.GetIdentityResources())
        .AddInMemoryApiResources(Security.IdentityConfig.GetResources())
      #region ids4 4.X 新特性 
        .AddInMemoryApiScopes(Security.IdentityConfig.GetScopes())
        //.AddInMemoryApiScopes(Security.IdentityConfig.ApiScopes)
      #endregion
        .AddProfileService<Security.ProfileService>()
        .AddResourceOwnerValidator<Security.ResourceOwnerPasswordValidator>();
    }
  }
}

6、.NET 5 Policy 策略授权配置【\AuthService\Security\ResourceOwnerPasswordValidator.cs】
添加了new Claim("super_admin", "true") 

private Claim[] GetUserClaims(UserDto user)
{
  if (user.user_name.ToString() == "admin")
  {
    return new Claim[]
    {
      new Claim("user_id", user.id.ToString()),
      new Claim("user_name", user.user_name.ToString()),
      new Claim("real_name", user.real_name.ToString()),
      #region Policy
      new Claim("super_admin", "true"),
      #endregion
      new Claim(JwtClaimTypes.Name,user.user_name),
      new Claim(JwtClaimTypes.Role, user.role == null ? "customer" : user.role)
 };
  }
  else
  {
    return new Claim[]
    {
      new Claim("user_id", user.id.ToString()),
      new Claim("user_name", user.user_name.ToString()),
      new Claim("real_name", user.real_name.ToString()),
      new Claim(JwtClaimTypes.Name,user.user_name),
      new Claim(JwtClaimTypes.Role, user.role == null ? "customer" : user.role)
    };
  }
}

*
*
*
*
*
*
*

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
.NET Core 中实现 OAuth2,可以使用 IdentityServer4 这个第三方库。IdentityServer4 是一个基于 OpenID Connect 和 OAuth2 协议的身份认证和授权框架。以下是实现步骤: 1. 安装 IdentityServer4 使用 NuGet 安装 IdentityServer4 包: ``` Install-Package IdentityServer4 ``` 2. 配置 OAuth2 在 Startup.cs 文件的 ConfigureServices 方法中,添加 IdentityServer4 服务: ```csharp services.AddIdentityServer() .AddInMemoryClients(new List<Client>()) .AddInMemoryApiResources(new List<ApiResource>()) .AddInMemoryIdentityResources(new List<IdentityResource>()) .AddTestUsers(new List<TestUser>()); ``` 这里使用了 InMemory 存储,也可以使用其他存储方式,如数据库存储。需要添加客户端、API 资源、身份资源和测试用户。 3. 配置授权 在 Startup.cs 文件的 Configure 方法中,添加 IdentityServer4 中间件: ```csharp app.UseIdentityServer(); ``` 然后,可以在控制器中添加 [Authorize] 属性来保护需要授权的 API。 4. 获取访问令牌 客户端可以使用 OAuth2 的授权码模式或者密码模式来获取访问令牌。这里以授权码模式为例: 客户端首先重定向到 IdentityServer4授权页面: ``` https://localhost:5001/connect/authorize?client_id=client&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A5002%2Fsignin-oidc&scope=api1 openid&state=123456 ``` 用户登录并授权后,将重定向回客户端的回调地址,并在 URL 中包含授权码。客户端使用这个授权码来获取访问令牌: ```csharp var client = new HttpClient(); var tokenResponse = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest { Address = "https://localhost:5001/connect/token", ClientId = "client", ClientSecret = "secret", RedirectUri = "https://localhost:5002/signin-oidc", Code = code, }); var accessToken = tokenResponse.AccessToken; ``` 以上是简单的 OAuth2 实现过程,在实际应用中需要根据具体业务需求进行更加详细的配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值