ASP.NET Core 中的身份认证及鉴权

ASP.NET Core高级之认证与授权(一)--JWT入门-颁发、验证令牌 正如每个人的家都需要锁门,每个系统也都需要对用户进行一些访问的控制,从而使系统更加地安全。 阅读详情

目录

知识准备

理解身份认证

身份认证(Authentication )

 鉴权(Authorization)

 IAuthorizeData

 Identity

认证功能配置

ConfigureServices

 AuthenticationScheme

Identity项目示例

创建项目

 配置认证与鉴权

配置服务

 启用中间件

 运行测试

总结

Identity

添加Identity功能

配置数据库连接

IdentityHostingStartup

配置RazorPage及静态文件

Startup.cs完整内容

生成数据库

生成迁移代码

功能测试

自定义UI


知识准备

ASP.NET Core 使用了不同传统Web程序的实现方式,在读本文之前,需要先了解ASP.NET Core的运作方式。主要是将传统Web中的模块(IHttpModule)和处理器(IHttpHandler)合并成了中间件(Middleware),以下ASP.NET Core 中间件的官方解释,以及如何进行代码迁移,不了解的小伙伴可以点开学习一下,这里不再重复。
ASP.NET Core Middleware | Microsoft Docs

Migrate HTTP handlers and modules to ASP.NET Core middleware | Microsoft Docs

Identity使用的RazorPage的实现,有关RazorPage请参考:

Introduction to Razor Pages in ASP.NET Core | Microsoft Docs


理解身份认证

ASP.NET Core 自带的安全管理分为两部分,一个是身份认证(Authentication ),另一个是鉴权(Authorization)。身份认证(Authentication )用于用户的登录登出,鉴权(Authorization)用于权限控制。这两个都是以相应的中间件(Middleware)来表示的。

身份认证(Authentication )

对于用户登录ASP.NET Core提供了多种认证方式,不过没找到具体的文档说明,这里参照源码总结了一下,大致分成四大类:

  1. 表单认证
  2. JWT认证
  3. 远程第三方认证
  4. 使用系统认证

这四类认证方式都实现了IAuthenticationHandler接口,但实际使用中并不直接在代码中操作这些具体的实现,可能是这个原因,微软的文档中并没有具体提及,AuthenticationHandler类结构图如下:

 鉴权(Authorization)

同样鉴权也有四种实现,分别是:

  1. 基于条件断言的,比如级别达到多少的可以访问。
  2. 防匿名的,比如某些功能需要登录才能使用。
  3. 基于用户的,比如某些指定的用户才可以使用。
  4. 基于角色的,比如某一类型的用户。

 IAuthorizeData

IAuthorizeData表明了具体资源的权限特征,实际项目中使用AuthorizeAttribute来表示。在鉴权的时候主要用到两个属性:Policy和Roles,这两个属性确定最终使用哪个鉴权方式。比如两个属性都不指定就是防匿名方式,指定Policy就是条件断言的方式。

比如在类申明中指定角色:

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
}

 Identity

Identity是基于表单认证的一套用户管理组件,包括用户登录(含第三方登录)、用户管理的定义和操作接口,以及相应的用户界面。Identity通常使用EntityFramkeworkCore作为持久层,将用户数据保存到关系数据库中。


认证功能配置

ConfigureServices

虽然认证中间件(AuthenticationMiddleware)是ASP.NET Core 内置的,但因为有多种认证方式,所以在应用启动时要作相应的配置。比如表单验证时的登录页面、登录出链接、保存凭据的Cookie名等。好在ASP.NET Core 给每种认证方式都提供了相应的扩展方法,可以轻松地进行配置。比如添加表单验证,登录页为/Login

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options=> {
                options.LoginPath = "/Login";
            });
            services.AddControllersWithViews();
        }

 AuthenticationScheme

AuthenticationScheme是个字符串,跟每一种验证方式一一对应。不过,AuthenticationScheme跟Middleware一样,都没有使用接口进行约束,而是都遵守一同一个约定,每个验证组件中提供一个AuthenticationScheme 的常量,比如提供:

   public static class FacebookDefaults
    {
        /// <summary>
        /// The default scheme for Facebook authentication. The value is <c>Facebook</c>.
        /// </summary>
        public const string AuthenticationScheme = "Facebook";

        /// <summary>
        /// The default display name for Facebook authentication. Defaults to <c>Facebook</c>.
        /// </summary>
        public static readonly string DisplayName = "Facebook";

        /// <summary>
        /// The default endpoint used to perform Facebook authentication.
        /// </summary>
        /// <remarks>
        /// For more details about this endpoint, see https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login.
        /// </remarks>
        public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v8.0/dialog/oauth";

        /// <summary>
        /// The OAuth endpoint used to retrieve access tokens.
        /// </summary>
        public static readonly string TokenEndpoint = "https://graph.facebook.com/v8.0/oauth/access_token";

        /// <summary>
        /// The Facebook Graph API endpoint that is used to gather additional user information.
        /// </summary>
        public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v8.0/me";
    }

 AuthenticationScheme通常是由相应的验证组件提供的扩展方法中自动调用的,但在多认证系统方式的系统中,需要指定通过AuthenticationScheme指定默认的认证系统。比如前边的ConfigService方法中,指定表单认证为默认认证方式。


Identity项目示例

创建项目

为了便于理解,我们从最简单的项目开始。我们在Visual Studio里创建一个空白Web项目,运行环境选择3.1,如图所示:

接下来,我们增加两条EndPoint,一条用于模拟登录,另一条模拟管理:

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });

//新增两条终结点

                endpoints.MapGet("/Account/Login", async context =>
                {
                    await context.Response.WriteAsync("Login");
                });
                
                endpoints.MapGet("/Manage", async context =>
                {
                    await context.Response.WriteAsync("Manage");
                });
            });

 配置认证与鉴权

配置服务

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
            services.AddAuthorization();
        }

 启用中间件

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //……

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

            app.UseEndpoints(endpoints =>
            {
                //……
                //使用RequireAuthorization()方法,对manage请求启用默认鉴权
                endpoints.MapGet("/Manage", async context =>
                {
                    await context.Response.WriteAsync("Manage");
                }).RequireAuthorization();
            });
        }

 运行测试

等Hello World出现后,在浏览器地址栏里输入:https://localhost:44362/manane,就会跳到模拟的登录页:

总结

此时我们已经让 ASP.NET Core 身份认证及鉴权生效,并开始工作。当然这里并没有实现登录等功能,如果要实现完整功能还需要写很多代码,不过这并不是我们目的,到此只要知道怎么工作的就行了。


Identity

添加Identity功能

前边我们演示了一个最简单的认证鉴权功能。接下来我们通过增加Identity来实现完整的功能,为了省事,我们使用Visual Studio来添加:

 弹出框中选择标识,点击添加:

 添加一个下文和一个用户类,点击添加:

 添加成功后,会自动添加相关依赖包,及需要的项目文件:

配置数据库连接

默认使用的Sql Server的驱动,且自动更新了配置,我们将连接字符串改成下边的样子:

appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

IdentityHostingStartup

加完标识后会自动生成一个IdentityHostingStartup.cs的文件,里边配置了数据库上下文及Identity,并通过assembly标注附加到启动项:

 [assembly: HostingStartup(typeof(WebApplication2.Areas.Identity.IdentityHostingStartup))]
namespace WebApplication2.Areas.Identity
{
    public class IdentityHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices((context, services) => {
                services.AddDbContext<WebApplication2Context>(options =>
                    options.UseSqlServer(
                        context.Configuration.GetConnectionString("WebApplication2ContextConnection")));

                services.AddDefaultIdentity<WebApplication2User>(options => options.SignIn.RequireConfirmedAccount = true)
                    .AddEntityFrameworkStores<WebApplication2Context>();
            });
        }
    }
}

配置RazorPage及静态文件

Startup里添加RazorPage中间件:

            services.AddRazorPages();

 使用静态文件:

app.UseStaticFiles();

添加映射:

endpoints.MapRazorPages();

Startup.cs完整内容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using WebApplication2.Areas.Identity.Data;
using WebApplication2.Data;

namespace WebApplication2
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
        }

        // 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();
            }
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });

                endpoints.MapGet("/Account/Login", async context =>
                {
                    await context.Response.WriteAsync("Login");
                });

                endpoints.MapGet("/Manage", async context =>
                {
                    await context.Response.WriteAsync("Manage");
                }).RequireAuthorization();

                endpoints.MapRazorPages();
            });
        }
    }
}

生成数据库

到目前为止程序能运行了,只是还不能登录,因为数据库还没创建。下边开始一步步添加数据库、

生成迁移代码

打开软件包控制台,输入以下命令:

Add-Migration Identity_Init

生成数据库:

Update-Database

功能测试

为了方便起见,先关闭密码策略

    public class IdentityHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices((context, services) =>
            {
                services.AddDbContext<WebApplication2Context>(options =>
                    options.UseSqlServer(
                        context.Configuration.GetConnectionString("WebApplication2ContextConnection")));

                services.AddDefaultIdentity<WebApplication2User>(options =>
                {
                    options.SignIn.RequireConfirmedAccount = false;
                    options.Password.RequireDigit = false;
                    options.Password.RequireLowercase = false;
                    options.Password.RequireNonAlphanumeric = false;
                    options.Password.RequireUppercase = false;
                    options.Password.RequiredLength = 6;
 
                    
                })
                    .AddEntityFrameworkStores<WebApplication2Context>();
            });
        }
    }

编译,在VS中起动,打开下边的链接,注册一个账号:

https://localhost:44359/Identity/Account/Register

因为没有限制,注册完就可以使用了。打开下边的链接,就可以修改自己的信息了。

https://localhost:44359/identity/account/manage

自定义UI

由于自带的UI并没有提供语言包,所以如果换成中文,需要使用自己的UI,我们可以重新添加标识,生成所需要的页面,在添加界面上勾选替代所有文件。

添加完成后,这些文件就全部在解决方案里了,我们尝试改其中的一个文件,比如Identity/Account/Manage/Index.cshtml.cs,给UserName属性加上Display属性,修改Input中的PhoneNumber的Display:

然后编译运行,查看效果:

至此Identity功能就算完成了。

ASP.NET Core WebAPI基于IdentityServer4实现Token令牌身份认证 一、课程介绍 开发提供数据的WebApi服务,最重要的是数据的安全性。那么对于我们来说如何确保提供的API服务的数据安全将会是需要思考的问题。在ASP.NET WebApi中我们应该如何保证我们的接口安全呢? 本次分享课程阿笨给大家分享的在ASP.NET Core中使用的是目前最流行、功能最强大的身份授权以及访问控制的解决方案——IdentityServer4(认证和授权),它是一套专注于... 阅读详情

相关推荐

课程3:ASP.NET Core 身份验证 - Cookie

身份验证在MSDN叫做Authorization,其目的就是验证Http请求,只有验证通过,才能访问特定的资源。 在Asp.Net Core提供非常多的Authorization方式。 在MSDN官方文档,我们也可以看到有以下的验证方式【截图是Asp.Net Core 7.0,各个版本有差异】:今天我们重点来,讲解Cookies验证,这是我们比较经常用到的方式之一。

成长的足迹 1707

【ASP.NET Core 基础知识】--身份验证和授权--用户认证的基本概念

用户认证是一个验证用户身份的过程,以确保用户是他们声称的那个用户。这通常涉及到用户提供用户名和密码,或者其他的身份验证信息,以证明他们有权访问特定的系统、服务或信息。用户认证是网络安全的重要组成部分,它可以防止未经授权的访问,保护用户的个人信息和企业的敏感数据。ASP.NET CORE 中的身份验证系统是一个强大的安全框架,它可以帮助开发人员保护他们的应用程序和用户数据。它提供了一种机制,用于验证用户的身份,并授权用户访问特定的资源或服务。

喵叔 2359

ASP.NET Core Authentication认证实现方法

追本溯源,从使用开始     首先看一下我们通常是如何使用微软自带的认证,一般在Startup里面配置我们所需的依赖认证服务,这里通过JWT的认证方式讲解 public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(authOpt => { authOpt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; authOpt.DefaultChallengeScheme =

实战解读ASP.NET Core身份认证

长话短说:上文我们聊了ASP.NET Core 基于声明的访问控制到底是什么鬼? 今天我们乘胜追击:聊一聊ASP.NET Core 中的身份验证。 身份验证是确定用户身份的过程。授权是确定用户是否有权访问资源的过程。 1. 万变不离其宗 显而易见,一个常规的身份认证用例包括两部分: ① 对用户进行身份验证 ② 在未经身份验证的用户试图访问受限资源时作出反应 已注册的身份验证处理程序及其配置选项被称为“方案”,方案可用作一种机制,供用户参考相关处理程序的身份验证、挑战和禁止行为。 我们口头上.

寒冰屋的专栏 1060

图像配准(Image Registration)——深度学习方法

参考:https://www.cnblogs.com/carsonzhu/p/11188574.html

m0_46483236的博客 4万+

同济大学824复试全攻略:从笔试到面试的实战解析

本文详细解析同济大学824复试全流程,包括专业课笔试、外语听力与口语、专业外语笔试和专业综合面试的备考策略。重点分享数字信号处理、计算机网络等专业课的高效学习方法,以及专业外语速成和口语面试技巧,助力考生全面提升复试表现。

qq_27496129的博客 1055

ASP.Net Core实战——身份认证(JWT鉴权)

踩坑不背锅,.NET Core 试深浅 ASP.NetCore实战——JWT鉴权认证(Swagger实践) 什么是鉴权认证 常见鉴权方式 关于JWT认证 JWT认证流程 JWT组成 JWT实践 仅仅简单的使用JWT鉴权认证,有更好的想法欢迎留言交流 ...

iZaix的博客 3097

创建可视化机房

(3)窗户位置创建好以后需要对窗户的墙面镂空位置进行修补,具体操作为,选中镂空位置的顶点(这里必须是选择一个平面的顶点,不要跨平面选择),实际操作如下图:选择点以后,鼠标右键,选择【从顶点创建边/面】,或者按F键,随后对其他镂空位置进行相同操作;(2)将【物体模式】修改为【编辑模式】,选中-x对应面的所有顶点,移动顶点位置,其他放小调整按照同理,找到选中对应面的所有顶点,移动位置即可;调整动画事件轴上的线,选中关键帧的时间,调整模型的位置或者旋转角度,具体根据插入关键帧菜单选择的项进行模型的相关调整。

SmileBu丿㦌的博客 2068

揭秘ASP.NET Core 8身份认证机制:如何实现安全可靠的JWT鉴权方案

掌握ASP.NET Core 8 Web API开发实战精髓,深入解析JWT身份认证机制。涵盖Token生成、验证流程与安全策略配置,适用于前后端分离与微服务场景,实现高效可靠的用户鉴权方案,值得收藏。

FastProceed的博客 913

Cadence SIP Layout 简单教程-第一章

以摄像头模组软硬结合板为例,描述layout的整个完整过程,从而掌握基本技能。 第一章 准备工作 第一节 原理图不用说layout前需要绘制原理图,原理图不在本文讨论范围内,所以列为准备工作。 需要特别说明的是,绘制原理的最终目的是导出网络表,网络表中的重要参数footprint是让layout软件选择正确封装的关键,所以这里讲解一下原理图设置footprint的位置。在原理图中双击零件,...

whp1920的博客 1万+

GPU架构(1.1)--介绍 GPU的 VPU(Vision Processing Unit)架构

基于自研的 VPU(Vision Processing Unit)架构,专为高性能图形处理和深度学习设计。VPU 架构通过优化计算单元、内存层次结构、同步机制和指令流水线,提供了卓越的性能和能效。VPU 架构通过优化计算单元、内存层次结构、同步机制和指令流水线,提供了卓越的性能和能效。这种架构不仅适用于高性能图形处理,还广泛应用于深度学习、科学计算和边缘计算等领域。通过了解 VPU 架构的详细设计和工作原理,读者可以更好地利用这些先进的 GPU 技术,开发出高效、可靠的计算系统。

MHD0815的博客 1300

.net 基于Cookie的身份认证

.net 基于Cookie的身份认证 新建一个asp.net core web api项目 注册基于Cookie的身份认证服务 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { //重写身份认证失败的逻辑,默认是跳转到/Account/Login,这里改为直接返回401 options.Events.OnRedirectToLogin = c

m0_47659279的博客 845

PCL 直通滤波器【2026最新版】

PCL直通滤波器函数详解以及用于多字段滤波、强度滤波、获取某一时间范围内的点等高阶用法案例分享。博客长期更新,本文最近一次更新时间为:2026年3月11日。

点云侠的博客 40万+

[特殊字符]C# ASP.NET Core 前后端分离终极实战:JWT 身份认证与授权全流程(登录 + 鉴权 + 避坑)

JWT 全称,是一种轻量级、自包含的令牌,用于在前后端之间安全传输身份信息,前后端分离认证的首选方案。前后端分离的安全通行证,替代 Session/Cookie登录验证→生成 Token→前端存储→请求头携带→后端鉴权JWT 注册配置、登录生成 Token、[Authorize]鉴权中间件顺序、请求头格式、跨域配置、Token 不存敏感信息。

William_cl的博客 615

鲁棒控制理论 --- H∞ 控制(被裁篇)

鲁棒控制理论 --- H∞ 控制

记录老板的每次pua,分享领导每天的毒鸡汤... 6万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

详细说明Cookie权限认证

Cookie权限认证的详细教程

箫箫余汐的博客 393

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

AgentCPM在企业级.NET技术栈中的集成与部署方案

本文介绍了如何在星图GPU平台上自动化部署📑AgentCPM深度研报助手镜像,为企业级.NET技术栈集成AI能力提供方案。该方案的核心在于通过封装模型服务,使企业内部的.NET应用(如金融报告系统)能够便捷调用AI助手,实现自动化研报生成与内容润色,从而提升业务人员的工作效率与数据安全性。

weixin_35835018的博客 55

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

简单实用的授权鉴权策略ASP.NET Core 9.0 Identity

但经过多次尝试发现网上代码质量良莠不齐,很多版本和代码已经废弃,包括deepseek里面的代码,也不知道是我输入的问题不完整还是其他问题,deepseek给出的解决方案完全不能用,无奈只好硬着头皮再去看官方文档,经过更改测试拿到最终有效的版本。3.添加声明(claims)我们用 await UserManager.AddClaimAsync(auser, new Claim("Permission", "Canwrite"))// 获取用户所有角色。//这里通过验证角色和授权检查的功能代码。

swelltan的专栏 901

Asp.net Core IdentityServer4 入门教程(一):概念解析

目录 1、IdentityServer4 是什么 2、什么是OpenID和OAuth 2.0协议 3、IdentityServer4 可以用来做什么 其他 1、IdentityServer4 是什么 IdentityServer4 是使用 ASP.NET Core实现...

weixin_30396699的博客 769

如何使用active-directory-aspnetcore-webapp-openidconnect-v2实现企业级用户认证

active-directory-aspnetcore-webapp-openidconnect-v2是一个功能强大的ASP.NET Core Web应用模板,专为企业级用户认证设计。它支持多种登录场景,包括组织内用户、多组织用户、个人微软账户以及主权云环境,同时还能安全调用Web API如Microsoft Graph。 ## 为什么选择active-directory-aspnetcore-

gitblog_00080的博客 478

基于 .NET Core 的 Web API 开发中常用鉴权技术概念和原理详解及举例

在 .NET Core 中,鉴权的核心是通过和授权中间件(Authorization Middleware)实现的。ASP.NET Core Identity 提供了处理用户身份认证和授权的功能,而授权中间件则允许你对用户访问特定资源的权限进行控制。用户发起请求,携带身份验证信息(如用户名、密码、JWT Token 等)。中间件验证用户的身份是否合法。如果认证通过,根据用户角色或声明进行鉴权。如果鉴权通过,继续执行请求的处理逻辑,否则返回未授权的响应。

百锦再的博客 1万+

ASP.NET Core 3.1中使用JWT身份认证

文章目录1、关于Authentication与Authorization2、整个认证流程是怎样的? 1、关于Authentication与Authorization 我相信在aspnet core中刚接触甚至用了段时间这两个概念的时候都是一头雾水的,傻傻分不清。 认证(Authentication)和授权(Authorization)在概念上比较的相似,且又有一定的联系,因此很容易混淆。 认证(A...

Jonny的博客 6306

ASP.NET CORE中使用Cookie身份认证

大家在使用ASP.NET的时候一定都用过FormsAuthentication做登录用户的身份认证,FormsAuthentication的核心就是Cookie,ASP.NET会将用户名存储在Cookie中。 现在到了ASP.NET CORE的时代,但是ASP.NET CORE中没有FormsAuthentication这个东西,那么怎么做身份认证呢?答案是ASP.NET CORE已经为我们内置了Cookie身份认证的功能,而且使用起来非常方便,注意本文是基于ASP.NET CORE 2.0版本来阐述Coo

极客神殿 1742

【ASP.NET Core】身份认证——Identity标识框架指南

本文介绍关于Identity标识框架的指南,从底层架构开始,扩展到如何应用

Arabys的博客 1274

在ASP.NET Core中实现一个Token base的身份认证

基于Token的身份认证就是应对这种变化而生的,它更开放,安全性也更高。基于Token的身份认证有很多种实现方式,但我们这里只使用微软提供的API。

dotNET跨平台 2290
上一篇: net core应用程序中启用app.config
下一篇: 软件开发资源整理
鸡窝里的毛
博客等级 码龄22年 58粉丝 42原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值