SSO单点登录系统WEB Service代码

CAS 实现单点登录(SSO)基本实现流程(一) 单点登录(Single Sign On),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。   CAS (Central Authentication Service),中央认证服务。CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架 阅读详情

ssoWebMethod/sso.asmx

-------------------------------------------------------------------------

<%@ WebService Language="C#" CodeBehind="~/App_Code/sso.cs" Class="sso" %>

ssoWebMethod/web.config

<?xml version="1.0"?>
<!--
    注意: 除了手动编辑此文件以外,您还可以使用
    Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
     “网站”->“Asp.Net 配置”选项。
    设置和注释的完整列表在
    machine.config.comments 中,该文件通常位于
    /Windows/Microsoft.Net/Framework/v2.x/Config 中
-->
<configuration>
  <appSettings>
    <add key="ClientIPZone" value="201.224.133.123" />
  </appSettings>
 <connectionStrings>
  <add name="ssoDatabase" connectionString="server=222.222.222.222;database=db_sso;uid=sso2;pwd=sz22223121;" providerName="System.Data.SqlClient"/>
 </connectionStrings>
 <system.web>
  <!--
            设置 compilation debug="true" 将调试符号插入
            已编译的页面中。但由于这会
            影响性能,因此只在开发过程中将此值
            设置为 true。
        -->
  <compilation debug="true"/>
  <!--
            通过 <authentication> 节可以配置 ASP.NET 使用的
            安全身份验证模式,
            以标识传入的用户。
        -->
  <authentication mode="Windows"/>
  <!--
            如果在执行请求的过程中出现未处理的错误,
            则通过 <customErrors> 节可以配置相应的处理步骤。具体说来,
            开发人员通过该节可以配置
            要显示的 html 错误页
            以代替错误堆栈跟踪。

        <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
            <error statusCode="403" redirect="NoAccess.htm" />
            <error statusCode="404" redirect="FileNotFound.htm" />
        </customErrors>
        -->
    <customErrors mode="Off"></customErrors>
 </system.web>
</configuration>
----------------------------------------------------------------------------------------------

ssoWebMethod/App_Code/sso.cs

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Configuration;
using System.Xml;
using System.IO;
/// <summary>
/// SSO系统
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class sso : System.Web.Services.WebService
{
    public sso()
    {
        //如果使用设计的组件,请取消注释以下行
        //InitializeComponent();
    }

    #region public

    /// <summary>
    /// 获取用户在应用系统中的登录帐号(密码暂时不返回)
    /// 返回noneLogin表示未登录,此时转入应用系统对应的登录页面..
    /// </summary>
    /// <param name="Token"></param>
    /// <returns></returns>
    [WebMethod]
    public String GetLoginByToken(String Token)
    {
        //根据Token读取对应的原业务系统的登录用户名与密码,并加密返回
        String result = "noneLogin";

        using (SqlConnection conn = new SqlConnection(ConnectionString))
        {
            conn.Open();

            String sql;
            sql = "SELECT AppsUsers.AppLoginId ";
            sql += "FROM AppToken ";
            sql += "INNER JOIN AppsUsers ";
            sql += "ON AppToken.AppId = AppsUsers.AppId AND AppToken.ssoUserId = AppsUsers.ssoUserId ";
            sql += "WHERE AppToken.Token = @Token";

            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.Add(new SqlParameter("@Token", Token));

            SqlDataReader dr = cmd.ExecuteReader();
            if (dr.Read())
            {
                //result = "LoginId=" + dr["AppLoginId"].ToString().Trim() + ";LoginPwd=" + dr["AppPassword"].ToString().Trim();
                result = dr["AppLoginId"].ToString().Trim();
            }
            dr.Dispose();
            cmd.Dispose();
        }

        return result;
    }

    /// <summary>
    /// 删除令牌。
    /// 成功返回true,否则返回false
    /// </summary>
    /// <param name="Token"></param>
    /// <returns></returns>
    [WebMethod]
    public Boolean TokenLost(String Token)
    {
        Boolean result = false;
        using (SqlConnection conn = new SqlConnection(ConnectionString))
        {
            conn.Open();

            String sql = "DELETE FROM AppToken WHERE Token = @Token";
            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.Add(new SqlParameter("@Token", Token));

            Int32 line = cmd.ExecuteNonQuery();
            if (line == 1)
            {
                result = true;
            }
            cmd.Dispose();
        }
        return result;
    }

    /// <summary>
    /// 激活单点登录
    /// </summary>
    /// <param name="AppId">应用系统标识,由SSO开发人员提供</param>
    /// <param name="ssoUserId">单点登录ID号(局内用户列表ID,下拉列表选择)</param>
    /// <param name="LoginId">应用系统登录帐号</param>
    /// <param name="ClientIP">激活客户端IP地址</param>
    /// <returns>返回提示信息字符串</returns>
    [WebMethod]
    public String SSOActive(String AppId, String ssoUserId, String LoginId)
    {
        //1.判断对应的系统,用户是否已激活过
        Int32 result = m_CheckAppsUsers(AppId, LoginId);
        if (result == -1)
        {
            return "Web Service执行错误,请联络技术支持.";
        }
        else if (result == 1)
        {
            return "该帐户已经是单点登录帐户,不用再次激活.";
        }

        //2.激活
        Boolean active = m_InsertAppsUsers(AppId, Convert.ToInt32(ssoUserId), LoginId);
        if (!active)
        {
            return "帐号激活失败,请联络技术支持.";
        }
        return "单点登录已激活";
    }

    /// <summary>
    /// 获取局内用户列表,激活必须选择一个用户名
    /// 填充一个DropDownList,用于选择用户名
    /// </summary>
    /// <returns></returns>
    [WebMethod]
    public XmlNode GetSSOUsers()
    {
        DataTable dt = m_GetSSOUsers();
        String xmlstr = m_GetXmlStrFromDataTable(dt);

        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xmlstr);

        dt.Dispose();
        return doc;
    }

    /// <summary>
    /// 判断客户端IP地址是否为局内IP地址段
    /// true为局内IP,false局外IP
    /// </summary>
    /// <param name="ClientIP">客户端IP地址</param>
    /// <returns></returns>
    [WebMethod]
    public Boolean CheckIP(String ClientIP)
    {
        //判断IP是否为本局IP,否则不能激活
        if (ClientIP.IndexOf(ClientIPZone) == -1)
        {
            return false;
        }
        return true;
    }

    #endregion

    #region private

    /// <summary>
    /// 检查帐号是否已经激活
    /// </summary>
    /// <param name="AppId">应用系统标识,由SSO开发人员提供</param>
    /// <param name="AppLoginId">应用系统登录帐号</param>
    /// <returns>-1表示WEB方法执行失败,0表示未激活,1表示已激活</returns>
    private Int32 m_CheckAppsUsers(String AppId, String AppLoginId)
    {
        Int32 result = -1;
        using (SqlConnection conn = new SqlConnection(ConnectionString))
        {
            conn.Open();

            String sql;
            sql = "SELECT * FROM AppsUsers ";
            sql += "WHERE AppId = @AppId AND AppLoginId = @AppLoginId";
            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.Add(new SqlParameter("@AppId", AppId));
            cmd.Parameters.Add(new SqlParameter("@AppLoginId", AppLoginId));

            SqlDataReader dr = cmd.ExecuteReader();
            if (dr.Read())
            {
                result = 1;
            }
            else
            {
                result = 0;
            }
            dr.Dispose();
            cmd.Dispose();
        }
        return result;
    }

    /// <summary>
    /// 新增帐号关联
    /// </summary>
    /// <param name="AppId"></param>
    /// <param name="ssoUserId"></param>
    /// <param name="AppLoginId"></param>
    /// <returns></returns>
    private Boolean m_InsertAppsUsers(String AppId, Int32 ssoUserId, String AppLoginId)
    {
        Boolean result = false;
        SqlConnection conn = null;
        SqlTransaction trans = null;
        try
        {
            conn = new SqlConnection(ConnectionString);
            conn.Open();

            trans = conn.BeginTransaction();
            SqlCommand cmd = new SqlCommand();

            cmd.Transaction = trans;
            cmd.Connection = conn;
            cmd.CommandType = CommandType.Text;

            //新增应用程序激活
            String sql;
            sql = "INSERT INTO AppsUsers(AppId, ssoUserId, AppLoginId) ";
            sql += "VALUES(@AppId, @ssoUserId, @AppLoginId)";

            cmd.CommandText = sql;

            cmd.Parameters.Add(new SqlParameter("@AppId", AppId));
            cmd.Parameters.Add(new SqlParameter("@ssoUserId", ssoUserId));
            cmd.Parameters.Add(new SqlParameter("@AppLoginId", AppLoginId));

            cmd.ExecuteNonQuery();

            ////更新单点登录密码
            //sql = "UPDATE ssoUsers SET ssoPassword = @ssoPassword WHERE ssoUserId = @ssoUserId";
            //cmd.CommandText = sql;

            //cmd.Parameters.Clear();
            //cmd.Parameters.Add(new SqlParameter("@ssoPassword", ssoPassword));
            //cmd.Parameters.Add(new SqlParameter("@ssoUserId", ssoUserId));

            //cmd.ExecuteNonQuery();

            trans.Commit();

            cmd.Dispose();

            result = true;
        }
        catch
        {
            try
            {
                trans.Rollback();
            }
            catch (SqlException ex)
            {
                throw new Exception(ex.Message);
            }
            throw;
        }
        finally
        {
            if (conn != null)
                conn.Dispose();
            if (trans != null)
                trans.Dispose();
        }
        return result;
    }

    /// <summary>
    /// 获取单点登录预设帐号列表
    /// </summary>
    /// <returns></returns>
    private DataTable m_GetSSOUsers()
    {
        DataTable dt = new DataTable();
        SqlConnection conn = null;
        try
        {
            conn = new SqlConnection(ConnectionString);
            conn.Open();

            String sql = "SELECT * FROM ssoUsers ORDER BY ssoUserName ASC FOR XML AUTO";
            SqlDataAdapter da = new SqlDataAdapter(sql, conn);
            da.Fill(dt);
            da.Dispose();
        }
        catch
        {
            throw;
        }
        finally
        {
            if (conn != null)
                conn.Close();
        }
        return dt;
    }

    /// <summary>
    /// 将DataTable转换成xml字串
    /// </summary>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static string m_GetXmlStrFromDataTable(DataTable dt)
    {
        String Result = "";

        foreach (DataRow row in dt.Rows)
        {
            Result += row[0].ToString();
        }
        Result = "<ssoUsers>" + Result + "</ssoUsers>";
        return Result;
    }


    /// <summary>
    /// SSO数据库连接
    /// </summary>
    private readonly String ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ssoDatabase"].ConnectionString;

    /// <summary>
    /// 客户端IP地址段
    /// </summary>
    private readonly String ClientIPZone = System.Configuration.ConfigurationManager.AppSettings["ClientIPZone"];

    #endregion
}

备注:ssoWebMethod为项目文件夹

 

SSO单点登录 阅读详情

相关推荐

单点登录SSO(一)

一、引子 问题1:什么是SSO?单点登录是什么? 回答1:SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。如: 如图所示,图中有4个应用,分别是Application1、Applicatio...

毛毛的专栏 2418

WebService的开发、发布及调用

一、VS中创建Web服务项目。 二、WebService生成发布 三、网站发布 四、故障及解决方法 五、如何访问WebService 六、Win7下的WebService   发布和使用WebService需要首先安装IIS服务,IIS的安装过程这里就不在叙述,baidu上到处都是。   1、  VS中创建Web服务项目 在VS中“文件”->“新建”->“网站”->“ASP.N

Lyncai的专栏 2308

shiro集成cas搭建SSO单点登录系统

在多应用系统中,登录一般是统一进行管理,在一个应用中登录了,在其他应用则不用登录,在任何一个应用进行退出,则当前用户已经在所有应用退出,即SSO单点登录。在大型网站新浪、淘宝,都实现了单点登录系统,避免了多个子系统都需要重复登录的现象。       成熟的Java单点登录系统有jasig cas server,与shiro集成,可以在登录时,跳到cas服务器,cas服务器连接用户的用户名、密

zesus的博客 5336

WebService、SSO----单点登录

WebService、SSOWS:一种比较常用的接口方式,目的,只是为了传输数据或者接口API(接口地址、接口名称、接口参数、接口返回值)传输的数据格式,多数是XML,但是ws中解析xml的方式比较特殊,而且是固定的,使用的技术使WSDL(XML解析语言) WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言。 WSDL 指网络服务描述...

djr2ss666666的博客 1308

【单点登录】什么是 SSO 与 CAS?

SSO 【转自】https://www.cnblogs.com/btgyoyo/p/10722010.html SSO 是英文 Single Sign On 的缩写,翻译过来就是单点登录。顾名思义,它把两个及以上个产品中的用户登录逻辑抽离出来,达到只输入一次用户名密码,就能同时登录多个产品的效果。 打个比方,SSO 和我们去迪士尼玩时购买的通票很像。 我们只要买一次通票,就可以玩所有游乐场内的设施,而不需要在过山车或者摩天轮那里重新买一次票。在这里,买票就相当于登录认证,游乐场就相当于使用一套

happydecai的博客 1852

聊聊单点登录(SSO)中的CAS认证

随着企业的发展,一个大型系统里可能包含 n 多子系统, 用户在操作不同的系统时,需要多次登录,很麻烦,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录。web 系统 由单系统发展成多系统组成的应用群,复杂性应该由系统内部承担,而不是用户。无论 web 系统内部多么复杂,对用户而言,都是一个统一的整体,也就是说,用户访问 web 系统的整个应用群与访问单个系统一样,登录/注销 只要1次就够了即单点登录,一种对于许多相互关联,但是又是各自独立的软件系统,提供访问控制的方法。

虚幻私塾 1365

20100525 学习记录:关于发布网站嵌套的bin文件夹 和 Could not create type....报错 = =+...

这还是上周的事情了,现在才总结。我的标题取的名字似乎也不准确 - = 事情缘由是我需要在我们网站下的根目录里放一个新的文件夹里面装webservice,并且这个webservice要用url可以独立访问(废话 - =) 结果我本地调试成功后放到服务器上部署时就是死活不好用,报错: Could not create type 'Service'. <%@ Web...

weixin_33796205的博客 2667

WebService实现用户注册与登录

WebService实现用户注册与登录,连接数据库,在Android端上测试

WS(webService) 的简单应用、实战案例

web service的简单应用 一:.主要实现四大大功能            1.在解决方案中创建一个webservice,并且调用            2.调用互联网上的webservice,(火车时刻表查询)            3.获取手机号码信息、判断qq号码是否在线 1.在解决方案中创建一个webservice,并且调用 service.asmx前台代码:

StrongBoy 1311

实现不同server的共享(相当于webservice,但不是webservice)

实现不同server的共享(相当于webservice,但不是webservice)

webservice整合到自己的web项目中一同发布

webservice整合到自己的web项目中一同发布,只需要tomcat就可以启动服务

Web Services 学习笔记

一 相关词语 WSDL Web Services Description Language 网络服务描述语言 SOAP 指简易对象访问协议 UDDI Universal Description, Discovery and Integration 通用描述、发现与集成服务 二 举例说明 <message name="getTermReq...

xie__jin__cheng的博客 353

化学科学催化反应产率预测之Transformer建模SMILES(Datawhale AI 夏令营)

循环神经网络:由于所有的前文信息都蕴含在一个隐向量中,随着序列长度的增加,早期的上下文信息会逐渐被遗忘。卷积神经网络:受限的上下文窗口在建模长文本时存在天然不足。需要多层卷积操作才能处理长文本。在本篇文章中,我们学习了Transformer的基本架构及其在化学反应产率预测中的应用。通过利用Transformer的Encoder部分对SMILES进行建模,我们能够更有效地捕捉序列数据的特征,从而提高模型的预测性能。

不想宅的冷同学 1095

Spring boot 整合JWT + Security

什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。 传统Cookie+Session与JWT对比 ① 在传统的用户登录认证中,因为ht

答案的博客 807

ARTIX-7 GTP 3G-SDI 工程构建与调试实战

本文详细介绍了基于ARTIX-7 FPGA和GTP收发器的3G-SDI工程构建与调试实战。从基础概念解析到Vivado工程创建、GTP IP核配置、SDI IP核集成,再到系统集成与时钟域处理,提供了全面的技术指导。文章还分享了调试技巧、常见问题排查方法以及性能验证步骤,帮助开发者快速掌握3G-SDI视频传输技术的实现与优化。

weixin_30443813的博客 256

Linux-RGMII PHY 88E1512 驱动调试记录

1. 简介 1)开发板平台:创龙 AM5728 (tl5728-easy-evm) 2)PHY芯片:Marvell 88E1512 88E1512和88E1510都是一个系列的phy,采用marvell的通用phy驱动,驱动源码路径如下:drivers/net/phy/marvell.c 2. 应用场景 1)系统框图 AM5728连接两个PHY,PHY0的工作模式是 RGMII to Copper (RGMII到电口),PHY1的工作模式是 RGMII to SGMII。 两个PHY与处理器的连接方式都是

weixin_40407893的博客 2万+

SSO之CAS单点登录部署

项目之前用到单点登录,之前都是网上找了一些资料然后就用上了,中间也遇到了一些问题,这里总结一下,毕竟以后还是可能再用到这东西的。 这里摘抄下有关基本概念帮助后面理解CAS的实现1.基本概念:cookie,session,会话cookie,jssessionid cookie和session机制是为了解决HTTP协议的无状态而生的; cookie是客户端保存用户信息的机制; session是服务器保

记录成长的点点滴滴 6367

【MATLAB/Simulink】从模型到飞行:基于PX4与Rflysim的无人机MBD实战指南

本文详细介绍了基于MATLAB/Simulink与PX4、Rflysim的无人机模型开发与飞行控制实战指南。通过MBD(基于模型设计)方法,从建模、仿真到代码生成与硬件部署,实现无人机开发的高效闭环。文章涵盖开发环境搭建、动力学建模、控制算法实现及测试验证全流程,为无人机开发者提供实用技巧与优化建议。

weixin_30181209的博客 410

单点登录(SSO)

SSO单点登录 1.1 为什么需要单点登录 1.11 单系统登录机制 我们假设浏览器第一次请求服务器需要输入用户名与密码验证身份,服务器拿到用户名密码去数据库比对,正确的话说明当前持有这个会话的用户是合法用户,应该将这个会话标记为“已授权”或者“已登录”等等之类的状态,既然是会话的状态,自然要保存在会话对象session中,用户再次访问时,tomcat在会话对象中查看登录状态 多系统(分布式)登...

张三与王二麻子 5496

全网最全的AItium Designer 16下载资源与安装步骤

Altium Designer 除了全面继承包括Protel 99SE、Protel DXP在内的先前一系列版本的功能和优点外,还增加了许多改进和很多高端功能。该平台拓宽了板级设计的传统界面,全面集成了FPGA设计功能和SOPC设计实现功能,从而允许工程设计人员能将系统设计中的FPGA与PCB设计及嵌入式设计集成在一起。...

WQ的博客 1万+

手把手教你学simulink(42.1)--储能系统场景示例:基于Simulink的电池+超级电容器混合储能系统

混合储能系统(HESS)结合了电池和超级电容器的优点,能够在满足高功率需求的同时提供较长的持续放电时间。这种组合特别适合用于电动汽车、可再生能源发电系统、电网频率调节等应用场景。本项目将详细介绍如何在MATLAB/Simulink中搭建一个完整的基于电池和超级电容器的混合储能系统,并提供具体的代码实现和设计步骤。如果你需要实现更复杂的控制逻辑,可以使用MATLAB Function模块。以下是一个简单的例子,展示了如何在该模块中实现一个条件逻辑,以分配电池和超级电容器的充放电任务。Matlab。

MHD0815的博客 542

多域单点登录SSO系统的实现

多域单点登录SSO系统的实现  天幻网新的规划中,将涉及到多域,如FFSKY.COM,FFSKY.CN等等,因此网上某些对同一域靠设置COOKIE的DOMAIN=".FFSKY.COM"的方式根本行8通,因此考虑用纯粹的PASSPORT的机制。 建设此系统前,我做了充分的准备工作,参考了网上N多的SSO系统实现的文章,包括国内和国外的,发现SSO系统有许多都是商业版的,基于JAVA的有许多现成

老汉--小庙和尚 2717

华为OD机试真题 新系统 2026-04-22 C++ 实现【小学生班长选举增强版】

9 月份开学第一天,小学某班级进行班长选举活动,班级共有 N 个学生,每个学生最多可投 3 票(对同一个人只能投一票),也可以弃权不投票,大家投票时写上对应学生的名字。 假设学生不存在重名。考虑到部分少数民族名字带分隔,且整体较长,同学在投票时为了方便,允许同学写全称,也可以只写其中的部分连续段。 例如班级里只有 2 个少数民族名称带点的同学:

MISAYAONE的博客 167

基于redis单点登录,SSO 单点登录,SSO CAS

查看传统的的登录方式 大家可以看到最后的用户信息 是存储到 session 中的。 现在有一个致命的问题 服务器中的session不是共享的,如果我们的项目的量级很大需要分布式服务器,那么就需要用户高频率的操作登录功能。这对于用户体验来说是残忍的,也是致命的。 传统登录问题: session默认是存储在当前服务器的内存中,如果是集群,那么只有登录那台机器的内存中才有这个session 比如说我在A机器登录,B机器是没有这个session存在的,所以需要重新验证 如何解决: 不管在那一台web服务器登

海里鱼的技术博客 636

十、Teigha.Net示例的源代码下载链接,以及英文的chm说明文件和相关案例

目录官方案例demo下载Teigha.net 英文版手册下载Teigha.net Entity实体中文翻译Teigha4.0 解决闪烁问题demo下载Teigha4.0 收录demo案例类似CAD看图王软件无AutoCAD环境下操作显示CAD文件的功能源码,整个示例模块源码 官方案例demo下载 在之前找到的官方案例3_03版本中包含32位与64位dll 其中的chm的说明文件内容也不完全,后面有更为详细的英文版的chm; 示例项目中,主要包括一个winfrom程序与控制台程序,OdWriteExMgd

... 3517

老版QQ原生表情gif动态

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

上一篇: 应用系统单点登录系统开发文档
下一篇: 分页存储过程及.NET代码
踏雪听雨
博客等级 码龄22年 72粉丝 178原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值