Role-based Security with Forms Authentication

Flask-Login实战避坑指南:Vue前后端分离下的登录态管理 Flask-Login是Python Web开发中用于用户会话管理的基础认证扩展,其核心原理是通过session绑定用户ID并配合user_loader回调实现请求级身份识别。它不处理密码校验或Token生成,而是专注‘已验证用户’在多次HTTP请求中的状态延续,技术价值在于轻量、可插拔且深度适配Flask上下文机制。典型应用场景包括图书管理系统、内部后台、教育平台等需角色隔离的B端应用;尤其在Flask与Vue前后端分离架构中,必须协同配置SameSite=None、Secure Cookie、withC 阅读详情

Introduction

Forms Authentication in ASP.NET can be a powerful feature. With very little code and effort, you can have a simple authentication system that is platform-agnostic. If your needs are more complex, however, and require more efficient controls over assets, you need the flexibility of groups. Windows Authentication gives you this flexibility, but it is not compatible with anything but Internet Explorer since it uses NTLM, Microsoft's proprietary authentication system. Now you must choose how to manage your assets: provide multiple login pages / areas and force users to register for each, or assign groups to users and limit access to pages / areas to particular groups. Obviously, you must choose the latter.

Role-based security in Forms Authentication is one thing Microsoft left out in this round for .NET, but they didn't leave you high-and-dry. The mechanisms are there, they're just not intuitive to code. This tutorial will cover the basics of Forms Authentication, how to adapt it to make use of role-based security, and how to implement role-based security on your site with single sign-ons.

Prerequisites

This tutorial is all about role-based security with Forms Authentication, a detail that Microsoft left out of .NET for this round. This tutorial will use different techniques that are almost completely incompatible with the standard Forms Authentication, save the setup, which we'll cover shortly.

To follow along in this tutorial, you'll need to create a database, a web application, several secured directories, and a few ASP.NET Web Forms (pages).

Creating the Database

We will create a simple database containing a flat table for this tutorial. Using the <credentials/> section of the Web.config file is not an option because no mechanism for roles is supported. For the purposes of brevity, the table we create will be very simple. You're welcome to expand the database to make use of relations (what I would do and actual do use on several sites) for roles. The implementation does start to get a little messy depending on how you do it, and the details are left up to you. This is merely a tutorial about developing role-based security.

So, choose what database management system you want to use (DBMS). For this tutorial, we'll choose the Microsoft Data Engine (MSDE) available with Visual Studio .NET, Office XP Developer, and several other products. We'll add one database, say web, and then add one table, say users. To the users table, we'll add three fields: username, password, and roles. Set the username field to the primary key (since it'll be used for look-ups and needs to be unique), and optionally create an index on the username and password fields together. If you're using Table-creation SQL Scripts, your script might look something like this:

CREATE 
DATABASE web

CREATE TABLE users
(
	username nvarchar(64) CONSTRAINT users_PK PRIMARY KEY,
	password nvarchar(128),
	roles nvarchar(64)
)

CREATE INDEX credentials ON users
(
	username,
	password
)

Feel free to add some credentials to your database, picking a few roles you think are good group names for your site, such as "Administrator", "Manager", and "User". For this tutorial, put them in comma-delimited format in the "roles" field like the following, pipe-delimited (|) table:

username|password|roles
"hstewart"|"codeproject"|"Administrator,User"
"joe"|"schmoe"|"User"

Take note to make the roles case-sensitive. Now let's move on to creating our pages necessary for role-based Forms Authentication.

Creating the Login Pages

If you haven't already done so, create a new Web Application, or attach to an existing Web Application, such as your web server's document root, "/". For this tutorial, we'll assume the Web Application resides in "/", though the procedure for any Web Application is the same.

Before we create any pages or setup our Web.config file, you must understand one thing: the login.aspx (or whatever you call your login page) must be public. If it isn't, your users will not be able to log-in, and could be stuck in an infinite loop of redirects, though I've not tested this and don't care to. So, this tutorial will assume that login.aspx is in "/", while we have two secured sub-directories, users and administrators.

First, we must create a Forms Authentication login system that supports roles. Because Microsoft did not provide for this easily, we will have to take over the process of creating the authentication ticket ourselves! Don't worry, it's not as hard as it sounds. A few pieces of information are needed, and the cookie has to be stored under the right name - the name matching the configured name for Forms Authentication in your root Web.config file. If these names don't match, ASP.NET won't find the Authentication Ticket for the Web Application and will force a redirect to the login page. For simplicity, we will put the code directly into the ASP.NET Web Form, which is easier to code for DevHood and should look something like the following:

Collapse
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<head>
	<title>Login</title>
</head>
<script runat="server">
// If you're using code-behind, make sure you change "private" to
// "protected" since the .aspx page inherits from the .aspx.cs
// file's class
private void btnLogin_Click(Object sender, EventArgs e)
{
	// Initialize FormsAuthentication, for what it's worth
	FormsAuthentication.Initialize();

	// Create our connection and command objects
	SqlConnection conn =
	 new SqlConnection("Data Source=localhost;Initial Catalog=web;");
	SqlCommand cmd = conn.CreateCommand();
	cmd.CommandText = "SELECT roles FROM web WHERE username=@username " +
	 "AND password=@password";

	// Fill our parameters
	cmd.Parameters.Add("@username", SqlDbType.NVarChar, 64).Value =
Username.Value;
	cmd.Parameters.Add("@password", SqlDbType.NVarChar, 128).Value =
	 FormsAuthentication.HashPasswordForStoringInConfigFile(
		Password.Value, "md5"); // Or "sha1"

	// Execute the command
	conn.Open();
	SqlDataReader reader = cmd.ExecuteReader();
	if (reader.Read())
	{
	 // Create a new ticket used for authentication
	 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
		1, // Ticket version
		Username.Value, // Username associated with ticket
		DateTime.Now, // Date/time issued
		DateTime.Now.AddMinutes(30), // Date/time to expire
		true, // "true" for a persistent user cookie
		reader.GetString(0), // User-data, in this case the roles
		FormsAuthentication.FormsCookiePath);// Path cookie valid for

	 // Encrypt the cookie using the machine key for secure transport
	 string hash = FormsAuthentication.Encrypt(ticket);
	 HttpCookie cookie = new HttpCookie(
		FormsAuthentication.FormsCookieName, // Name of auth cookie
		hash); // Hashed ticket

	 // Set the cookie's expiration time to the tickets expiration time
	 if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;

	 // Add the cookie to the list for outgoing response
	 Response.Cookies.Add(cookie);

	 // Redirect to requested URL, or homepage if no previous page
	 // requested
	 string returnUrl = Request.QueryString["ReturnUrl"];
	 if (returnUrl == null) returnUrl = "/";

	 // Don't call FormsAuthentication.RedirectFromLoginPage since it
	 // could
	 // replace the authentication ticket (cookie) we just added
	 Response.Redirect(returnUrl);
	}
	else
	{
	 // Never tell the user if just the username is password is incorrect.
	 // That just gives them a place to start, once they've found one or
	 // the other is correct!
	 ErrorLabel = "Username / password incorrect. Please try again.";
	 ErrorLabel.Visible = true;
	}

	reader.Close();
	conn.Close();
}
</script>
<body>
	<p>Username: <input id="Username" runat="server"
type="text"/><br />
	Password: <input id="Password" runat="server" type="password"/><br
/>
	<asp:Button id="btnLogin" runat="server" OnClick="btnLogin_Click"
	 Text="Login"/>
	<asp:Label id="ErrorLabel" runat="Server" ForeColor="Red"
	 Visible="false"/></p>
</body>
</html>

You'll notice above that we do one other thing with our passwords: we hash them. Hashing is a one-way algorithm that makes a unique array of characters. Even changing one letter from upper-case to lower-case in your password would generate a completely different hash. We'll store the passwords in the database as hashes, too, since this is safer. In a production environment, you'd also want to consider having a question and response challenge that a user could use to reset the password. Since a hash is one-way, you won't be able to retrieve the password. If a site is able to give your old password to you, I'd consider steering clear of them unless you were prompted for a client SSL certificate along the way for encrypting your passphrase and decrypting it for later use, though it should still be hashed.

Note: without using HTTP over SSL (HTTPS), your password will still be sent in plain-text across the network. Hashing the password on the server only keeps the stored password secured. For information about SSL and acquiring a site or domain certificate, see http://www.versign.com/ or http://www.thawte.com/.

If you don't want to store hashed passwords in the database, change the line that reads FormsAuthentication.HAshPasswordForStoringInConfigFile(Password.Value, "md5") to just Password.Value.

Next, we'll need to modify the Global.asax file. If your Web Application doesn't have one already, right-click on the Web Application, select "Add->Add New Item...->Global Application Class". In either the Global.asax or Global.asax.cs (or Global.asax.vb, if you're using VB.NET), find the event handler called Application_AuthenticateRequest. Make sure it imports / uses the System.Security.Principal namespace and modify it like so:

protected void Application_AuthenticateRequest(Object sender,
EventArgs e)
{
  if (HttpContext.Current.User != null)
  {
	if (HttpContext.Current.User.Identity.IsAuthenticated)
	{
	 if (HttpContext.Current.User.Identity is FormsIdentity)
	 {
		FormsIdentity id =
			(FormsIdentity)HttpContext.Current.User.Identity;
		FormsAuthenticationTicket ticket = id.Ticket;

		// Get the stored user-data, in this case, our roles
		string userData = ticket.UserData;
		string[] roles = userData.Split(',');
		HttpContext.Current.User = new GenericPrincipal(id, roles);
	 }
	}
  }
}

What's happening above is that since our principal (credentials - which are your username and roles) is not stored plainly as part of our cookie (nor should it, since a user could modify their list of role-memberships), it needs to be generated for each request. The FormsAuthenticationTicket is actually encrypted as part of a cookie using your machine key (usually configured in machine.config) and the FormsAuthentication module decrypts the tick as part of the user's identity. If you search long and hard enough on Microsoft MSDN web site, you'll find this documentation buried. We use the UserData to obtain the list of roles and generate a new principal. Once the principal is created, we add it to the current context for the user, which the receiving page can use to retrieve credentials and role-memberships.

Securing Directories with Role-based Forms Authentication

To make the role-based authentication work for Forms Authentication, make sure you have a Web.config file in your Web Application root. For the authentication setup, this particular Web.config file must be in your Web Application's document root. You can override the <authorization/> in Web.config files for sub-directories.

To begin, make sure your Web.config file has at least the following:

<configuration>
	<system.web>
		<authentication	mode="Forms">
			<forms name="MYWEBAPP.ASPXAUTH"
				loginUrl="login.aspx"
				protection="All"
				path="/"/>
		</authentication>
		<authorization>
			<allow users="*"/>
		</authorization>
	</system.web>
</configuration>

The FormsAuthentication name (MYWEBAPP.ASPXAUTH) above it arbitrary, although the name there and the name in the HttpCookie we created to hold the hashed FormsAuthenticationTicket must match, for even though we are overriding the ticket creation, ASP.NET still handles the authorization automatically from the Web.config file.

To control authorization (access by a particular user or group), we can either 1) add some more elements to the Web.config file from above, or 2) create a separate Web.config file in the directory to be secure. While, I prefer the second, I will show the first method:

<configuration>
	<system.web>
		<authentication mode="Forms">
			<forms name="MYWEBAPP.ASPXAUTH"
				loginUrl="login.aspx"
				protection="All"
				path="/"/>
		</authentication>
		<authorization>
			<allow users="*"/>
		</authorization>
	</system.web>
	<location path="administrators">
		<system.web>
			<authorization>
				<!-- Order and case are important below -->
				<allow roles="Administrator"/>
				<deny users="*"/>
			</authorization>
		</system.web>
	</location>
	<location path="users">
		<system.web>
			<authorization>
				<!-- Order and case are important below -->
				<allow roles="User"/>
				<deny users="*"/>
			</authorization>
		</system.web>
	</location>
</configuration>

The Web Application always creates relative paths from the paths entered here (even for login.aspx), using it's root directory as the starting point. To avoid confusion with that condition and to make directories more modular (being able to move them around without changing a bunch of files), I choose to put a separate Web.config file in each secure sub-directory, which is simply the <authorization/> section like so:

<configuration>
	<system.web>
		<authorization>
			<!-- Order and case are important below -->
			<allow roles="Administrator"/>
			<deny users="*"/>
		</authorization>
	</system.web>
</configuration>

Notice, too, that the role(s) is/are case-sensitive. If you want to allow or deny access to more than one role, delimit them by commas.

That's it! Your site is setup for role-based security. If you use code-behind, compile your application first. Then try to access a secure directory, such as /administrators, and you'll get redirected to the login page. If login was successful, you're in, unless your role prohibits it, such as the /administrators area. This is hard for the login.aspx page to determine, so I'd recommend a Session variable to store the login attempts and after so many times, return an explicit "Denied" statement. There is another way, however, which is discussed below.

Conditionally Showing Controls with Role-based Forms Authentication

Sometimes it's better to show / hide content based on roles when you don't want to duplicate a bunch of pages for various roles (user groups). Such examples would be a portal site, where free- and membership-based accounts exist and membership-based accounts can access premium content. Another example would be a news page that would display an "Add" button for adding news links if the current user is in the "Administrator" role. This section describes how write for such scenarios.

The IPrincipal interface, which the GenericPrincipal class we used above implements, has a method called IsInRole(), which takes a string designating the role to check for. So, if we only want to display content if the currently logged-on user is in the "Administrator" role, our page would look something like this:

<html>
<head>
  <title>Welcome</title>
  <script runat="server">
  protected void Page_Load(Object sender, EventArgs e)
  {
   if (User.IsInRole("Administrator"))
    AdminLink.Visible = true;
  }
  </script>
</head>
<body>
  <h2>Welcome</h2>
  <p>Welcome, anonymous user, to our web site.</p>
  <asp:HyperLink id="AdminLink" runat="server"
   Text="Administrators, click here." NavigateUrl="administrators/"/>
</body>
</html>

Now the link to the Administrators area of the web site will only show up if the current user is logged in and is in the "Administrator" role. If this is a public page, you should provide a link to the login page, optionally setting the QueryString variable called ReturnUrl to the path on the server you want the user to return to upon successful authentication.

Summary

This tutorial was created to help you understand the important of role-based security, as well as implement role-based security on your web site with ASP.NET. It's not a hard mechanism to implement, but it does require some know-how of what principals are, how credentials are authenticated, and how users / roles are authorized. I hope you have found this tutorial helpful and interesting, and that it leads you to implement role-based Forms Authentication on your current or upcoming site!

 
WEB应用中的身份验证(2)--Form身份验证Form-based Authentication 网上有很多关于此类文章,但是有很多文章将的含糊不清,让人看了很是郁闷,更有甚者竟然把没有测试的文章也帖出来,真不知道这些人怎么想的。。。哎~!废话少说,让我们开始把~~!这些话上次已经说完了^_^现在开始我们的Form-based Authentication吧,其实和BASIC基本上完全一样,就是拷贝~要搭建整个流程需要四个阶段:一、建立测试用数据库        我们这里用My 阅读详情

相关推荐

IATF16949核心职位全解析

TM / Top MgmtMR / QMRProcess OwnerQMQAQCSQECQEPQEPETEMEIEPM / PJMFMEA ModeratorMSA CoordinatorSPC CoordinatorCM / CCB内审员CP / CPK

weixin_49938552的博客 972

Spring Security(04)授权配置

授权 基本说明 授权指的是给用户某个操作的权限; 常见的权限的访问控制一般是 基于rpac (Role-Based Access Control)的 访问控制; Authentication 是springsecurity 中的非常重要的接口;能够获取登录用户的信息和授权的相关信息; 而授权的信息是通过 Collection<? extends GrantedAuthority> getAuthorities(); 此方法获取 GrantedAuthority 也只有一个返回Authority

愤怒的菜鸟博客 990

当AI学会自我验证:Chain-of-Verification如何杜绝错误决策?

2025年,大模型"幻觉"问题已成为企业落地AI的最大障碍之一——金融风控中1.2%的误判率可能导致千万级损失,医疗诊断中3%的错误可能危及生命,法律文书中5%的事实偏差可能引发合规风险。MetaAI与Google联合提出的**Chain-of-Verification(CoVe,验证链)**技术,让AI具备"自我审视"能力,通过结构化验证流程将幻觉率降低68%+,在复杂决策场景准确率提升至95%+。本文系统拆解CoVe的技术原理、实施路径与行业实战,为企业提供AI决策可靠性保障的完整方案。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1081

Web服务器使用基于纯文本表单的身份验证——.net(未完待续)

asp.net 表单验证方式 Asp.net的身份验证有有三种,分别是"Windows|Forms| Passport",其中又以Forms验证用的最多,也最灵活。 根据实际需求把用户分成不同的身份,就是角色,或者说是用户组,验证过程不但要验证这个用户本身的身份,还要验证它是属于哪个角色的。而访问授权是根据角色来设置的,某些角色可以访问哪些资源,不可以访问哪些资源等等。 For...

242

基于STM32与SimpleFOC实现直流无刷电机开环控制的实战指南

本文提供了一份基于STM32微控制器与SimpleFOC开源库实现直流无刷电机开环控制的详细实战指南。内容涵盖硬件连接、PlatformIO环境搭建、核心代码解析及上电测试,旨在帮助开发者快速验证硬件并理解开环控制的基本原理,为后续实现高性能的闭环FOC控制奠定基础。

xxx12的博客 960

网络攻防实验——网络监听

利用CAIN实现ARP监听。

Trieyes_of_feng的博客 3197

ASP.net(1.1)原理学习笔记--第十一章 安全性Security

Chapter 11. Security ASP.NET provides authentication and authorization services in conjunction with IIS, supporting Basic, Digest, and Windows authentication. Impersonation using client credentials i...

weixin_30244681的博客 1144

Hyper-V显卡直通实战:手把手解决Windows 11虚拟机错误码43(附完整参数配置)

本文详细解析了在Windows 11 Hyper-V虚拟机中配置显卡直通时遭遇错误码43的根源,并提供了从环境检查、核心PowerShell命令(如Set-VMGpuPartitionAdapter)配置到虚拟机内驱动替换的完整实战解决方案,帮助用户彻底解决显卡驱动无法加载的问题。

weixin_29238147的博客 899

认证与授权

在开发或者管理一个应用程序的时候,我们往往会看到两个名词——认证和授权,在英文中这两个词更为相近 —— authentication 和 authorization。尽管这两个术语经常出现在相同的上下文中,但是两者在概念上是非常不同的。 认证意味着确认你自己的身份,而授权意味着授予对系统的访问权限。简单来说,认证是验证你的身份的过程,而授权是验证你有权访问的过程。 什么是认证 认证是关于验证你的凭据,如用户名/邮箱和密码,以验证访问者的身份。系统确定你是否就是你所说的使用凭据。在公共和专用网络中,系统

顺其自然~专栏 3974

基于STM32设计的智能水产养殖系统(2025)_359

本设计提出并实现了一种基于STM32F103RCT6微控制器的智能水产养殖控制系统,针对传统水产养殖中人工依赖高、环境参数监测滞后、控制手段单一等问题,集成了TDS水质检测、水温检测、水位监测、自动喂食、自动充氧、换水控制与加热保温等功能。系统采用ESP8266模块实现WIFI联网,通过MQTT协议将关键数据上传至华为云物联网平台,支持Android手机APP和Windows上位机远程监测与控制。同时,系统具备本地LCD数据显示与蜂鸣器异常报警功能,支持本地按键控制操作。整套系统功能完善,响应灵敏,运行稳定

625

后仿真中《SDF反标必懂连载篇》之 <INTERCONNECT/IOPATH> 到底反标电路路径是哪里

对于SDF INTERCONNECT ENTRY 描述,我们在之前的文章有详解。读万卷书,行万里路。实践很重要。今天,搞一下SDF INTERCONNECT / IOPATH 延迟数据信息,究竟反标的是哪一路径延时?究竟在电路上一段段如何表现出延迟现象的呢?

那么菜的博客 2134

揭秘航空公司:核心业务系统如何确保您的每一次飞行无忧

航空公司、核心业务

CAAC_SKY的博客 925

【x265编码器】章节6——x265的码率控制

对于CRF模式而言,右边这部分是是固定值m_rateFactorConstant,在初始化的时候确定,跟分辨率,qCompress这个参数是外部可设参数,默认值0.6,因此QP的选择只跟编码复杂度有关,跟码率无关,编码复杂度越高,QP值越高,因此可以一定程度上说CRF模式是恒定质量的编码模式。其中Complex表示当前帧的编码复杂度,x265中用lookahead模块计算的SATD作为衡量当前帧的复杂度,c为模型参数,qscale是率失真优化中的拉格朗日乘子,R为编码当前帧需要的比特数。

vcvdv123的博客 1万+

Role-Based Security With Forms Authentication

http://support.microsoft.com/default.aspx?scid=kb;zh-cn;311495http://support.microsoft.com/kb/306590/ZH-CN/http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=433http://aspnet.4gu

RainyLin-SunnyLin的专栏 1054

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Role-based Security with Forms Authentication (By Heath Stewart. )

转自(http://www.codeproject.com/aspnet/formsroleauth.asp)IntroductionForms Authentication in ASP.NET can be a powerful feature. With very little code and effort, you can have a simple authentication

村里的程序员 847

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

[转贴]Forms authentication and role-based security

// Create the authentication ticketFormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(                                    1,                          //version                       

ldw701的专栏 932

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

05 claude code 提示词如何构建

所有模板均支持通过无硬性长度限制:提示词不规定压缩比例(如50%),仅要求信息完整性。双重防呆机制:Preamble 和 Trailer 双重禁止工具调用,确保压缩任务原子性。结构化输出:强制使用<analysis>和<summary>标签,便于后处理和审计。场景化区分:BASE(全量)、PARTIAL(局部)、UP_TO(前瞻)三种模板应对不同压缩需求。

m0_73980980的博客 696

工作中使用到的单词(软件开发)

1.エイリアス   alias 别名 powershell使用 get-help 命令时,会得到与此命令 相关(别名)的命令 2.プロキシ proxy 代 理 3.プロモート   promote 促进,提升   开发的系统新功能上线发布,有时会使用到这个词,比如 STプロモート 还有使用リリース这个词的。比如STリリース。个人认为两者含义相同。 4.見逃し み................................................................

sun0322 6万+

如何在SharePoint 2010中搭建Form-Based Authentication?

随着公司发展,越来越多的企业在使用SharePoint时,不仅仅满足于使用Windows AD的认证方式,在同时也配置了基于表单的Form-based认证使用。那我们就来看下在SharePoint环境中如何一步步的完成对Form-based Authentication的配置。

WarmSunshine7的博客 937

FoMs的定义

weixin_51982436的博客 487

Shiro---角色和权限的校验方法

一.角色校验 1.hasRole(String role) hasRole是判断是否具有某个角色:有就返回true,没有就返回false 2.hasRoles(List roles) 判断是否具有多个角色:返回值是一个boolean的数组,数组中的每一个元素代表了是否具有的角色 3.hasAllRoles(Collection roles) 判断是否具有多个角色:如果提供列表中没有用户所具有的角色,则返回false,如果都存在,返回true 4. subject.checkXxx() 也是判断用户是否具有角

Apple_Andy的博客 1074

Role-Based Security

Role-Based SecurityThe fundamental concept in role-based security is that privileges are assigned to defined categories of users (known as roles) rather than to individual users. When a user is

微软新技术 1576
上一篇: ASP.NET 安全认证----如何运用 Form 表单认证详解
下一篇: ASP.NET基于角色的窗体安全认证机制
liner0607
博客等级 码龄20年 13粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值