返回顶部
首页 > 资讯 > 数据库 >建立mongodb的登录认证功能
  • 864
分享到

建立mongodb的登录认证功能

2024-04-02 19:04:59 864人浏览 泡泡鱼
摘要

对于一个完善的数据库系统,必然是需要权限控制,当然mongoDB也不例外.没有认证的数据库已经被证明是******的一个突破口,所以我们无论是出于什么原因,数据库认证对于一个生产系统而言,至关重要.在Mon

对于一个完善的数据库系统,必然是需要权限控制,当然mongoDB也不例外.没有认证的数据库已经被证明是******的一个突破口,所以我们无论是出于什么原因,数据库认证对于一个生产系统而言,至关重要.

在MonGoDB 3.0 以后,用户登录的密码认证机制有:SCRAM-SHA-1(默认,基于加盐的应答式认证),MONGODB-CR(普通应答式认证,3.6废弃,4.0删除),x.509 Certificate(基于证书的SSL/TLS加密认证),LDAP Proxy(基于LDAP系统的鉴权认证,仅企业版支持),Kerberos(基于Kerberos鉴权,仅企业版支持),一般而言,默认的就已经很不错了.

然后mongodb还有一个内部鉴权策略,主要是防止数据被拦截,有:keyfile(基于SCRAM的应答式认证),x.509 Certificate(基于证书的SSL/TLS加密),对于内部来说,如非特殊情况,使用keyfile就足够了.


对单台数据库增加mongodb认证信息(基本认证知识)

首先要讲一讲的是,mongodb本身并没有要求一定要认证登录,也就是免认证直接登录是允许的,不过出于安全考虑的话,我们应该更加严谨一些,增加认证登录来使用,但是mongodb又不同于Mysqloracle的授权方式,比较奇怪.下面来看.

首先,也是要打开参数

#打开配置文件
vim /usr/local/mongodb/mongod_data_40001.conf
    .
    .
    .
#是否开启认证模式,现在开启来使用
auth = true
#关闭认证模式,和上面的冲突,之前是开启的,现在关闭了
#noauth = true
#指定集群认证文件,没开认证就不用指定,注释关闭即可,需要用openssl来生成,暂时不研究
#keyFile  = /data/mongodb/data/keyfile
#指定访问地址,3.4之前默认全网,之后则默认是127.0.0.1,但是在3.6之后必须制定这个参数才能启动.配置0.0.0.0代表全网匹配
#bind_ip=0.0.0.0

参数打开了,需要重启一下登录

#登录进去操作
mongo -port=40001
MongoDB shell version v3.4.16-rc0
connecting to: mongodb://127.0.0.1:40001/
MongoDB server version: 3.4.16-rc0
#操作一下
> show dbs
2018-07-17×××5:04:34.009+0800 E QUERY    [thread1] Error: listDatabases failed:{
    "ok" : 0,
    "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
    "code" : 13,
    "codeName" : "Unauthorized"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:788:19
shellHelper@src/mongo/shell/utils.js:678:15
@(shellhelp2):1:1
>

好像报错了,但是请淡定,这是正常现象,因为之前默认是免认证,现在开启了认证,你又没创建用户,那肯定是报错的,不过不用担心,因为你原本是没用户密码的,所以是可以新建的.

但是要注意,在初始无账户密码状态下,只能通过登录127.0.0.1这个地址你才能创建用户和密码,所以就需要注意参数bind_ip的值了.

#进入admin数据库,也是当前用户认证库
> use admin
switched to db admin
#授权
> db.createUser({user:"adminuser",pwd:"admin123",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
Successfully added user: {
    "user" : "adminuser",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}
#再创建多一个试试
> db.createUser({user:"root",pwd:"root123",roles:[{role:"root",db:"admin"}]})
2018-07-17×××5:05:04.167+0800 E QUERY    [thread1] Error: couldn't add user: not authorized on admin to execute command { createUser: "root", pwd: "xxx", roles: [ { role: "root", db: "admin" } ], digestPassWord: false, writeConcern: { w: "majority", wtimeout: 600000.0 } } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.createUser@src/mongo/shell/db.js:1292:15
@(shell):1:1
>

又报错了?没错,这个时候你已经有用户了,所以就拒绝你的操作了,你要先认证一下你自己刚建好的用户了

#认证一下你刚才创建的用户
> db.auth("adminuser","admin123")
1
> use admin
switched to db admin
#再次创建用户
> db.createUser({user:"root",pwd:"root123",roles:[{role:"root",db:"admin"}]})
Successfully added user: {
    "user" : "root",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}
> db.auth("root","root123")
1
> show dbs
admin  0.000GB
local  0.000GB
>

这次没问题了,解决了问题,要想创建更多用户,甚至细化到个别数据库来创建用户,你可以这样:

use foo;
db.createUser({user: 'foo', pwd: 'bar', roles: [{role: 'readWrite', db: 'foo'}]})
db.auth('foo', 'bar')


这里就涉及一个mongodb特别的知识点---认证库的概念.

mongodb和别的数据库不同,认证的信息是细化到库的,而并不是像mysql,oracle,SQL Server那样集中管理,都存放到一个user表.

不同数据库的用户可以存放到不同的数据库,例如:foo库的用户foo只存放在foo库里面,他不能登录admin库,在admin库里面是没有foo用户信息.同理,admin库的用户root是不存在于foo库的,但是root用户是能登陆foo的,原因是root用户的权限更大一些(废话).但是,你如果把foo库删除了,那么foo用户也会"顺便"被一起删除了,也就是这个用户和这个库也彻底不再了.

所以我们有两种不同的理念,基于方便管理的概念来说,我们应该集中管理,对于认证库这个概念,我们的思路应该把它们都建立在admin库更佳,然后再细分权限,删除库有时候可以只是删除登录用户就可以了.基于安全考虑问题,我们不能让一些废弃用户存在,因为mongodb的特性是没有create动作,只要有权限,就可以自动创建库和表的.


然后还有第二个mongodb的知识点---角色权限管理

mongodb创建的用户是按role角色来区分权限的,跟我们熟悉的oracle和sql server相似(mysql8.0后才支持角色管理),这点倒不是特别了.至于有什么role选择呢,你可以show roles看看.我们主要常用的有全局超级管理员userAdminAnyDatabase(也是我们第一个需要创建的用户权限),readWriteAnyDatabase,readWrite,readAnyDatabase,read,root等.

每一个角色代表着有不同的权限集合,可以细化到每个用户的权限范围,例如read就只能find查询,readWrite就是典型的增删查改了,还有我们熟悉的root就是完全控制权限了.

mongos> show roles
{
    "role" : "__system",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "backup",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    .
    .
    .
}
{
    "role" : "read",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "readAnyDatabase",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "readWrite",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "readWriteAnyDatabase",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "restore",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "root",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "userAdmin",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}
{
    "role" : "userAdminAnyDatabase",
    "db" : "admin",
    "isBuiltin" : true,
    "roles" : [ ],
    "inheritedRoles" : [ ]
}

这里就不详细解析了,大多数和字面意思差不多,非常赞.


既然创建完成了,我们尝试下带用户名的登陆方式:

[root@localhost ~]# mongo 10.21.14.16:40001/admin -u root -p "root123"
MongoDB shell version v3.4.16-rc0
connecting to: mongodb://10.21.14.16:40001/admin
MongoDB server version: 3.4.16-rc0
> show dbs
admin  0.000GB
local  0.000GB
>

可以正常使用了.


当然了,用户就必须是可以修改和删除信息的,这里不详细讲,附上命令参考

#假设我们新建了一个用户ttt,这里就不解析了
>use admin
>db.createUser({user:"ttt",pwd:"123",roles:[{role:"root",db:"admin"}]})
>db.auth("ttt","123")
#查看现在所有的用户信息,也就多了个ttt了.
> db.system.users.find()
{ "_id" : "admin.adminuser", "user" : "adminuser", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "jLubKc6ODHMxCnjFeeJuog==", "storedKey" : "l1cL39bnvkw2fecw1DHdKM0TM7s=", "serverKey" : "ZD+EZymr8OhlwMZ/0h35Qn8QHE4=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
{ "_id" : "admin.root", "user" : "root", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "Fx2BRB2ZIJeD2X+bvM0ZIg==", "storedKey" : "Yyo+vcxhv40vNXZwUNfnBTz×××30=", "serverKey" : "th4UbT+/aJcgOXvKx4TFDhX242k=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
{ "_id" : "admin.ttt", "user" : "ttt", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "X58qg8jiiM3ju8v8Cywu8A==", "storedKey" : "MO4lwHhFUn50Ja0/QCHeN4hObRQ=", "serverKey" : "N9iUXgshDP9beTD8pNKfrmtl0V0=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
#另一个命令也能看到
> db.getUsers()
[
    {
        "_id" : "admin.adminuser",
        "user" : "adminuser",
        "db" : "admin",
        "roles" : [
            {
                "role" : "userAdminAnyDatabase",
                "db" : "admin"
            }
        ]
    },
    {
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
            {
                "role" : "root",
                "db" : "admin"
            }
        ]
    },
    {
        "_id" : "admin.ttt",
        "user" : "ttt",
        "db" : "admin",
        "roles" : [
            {
                "role" : "root",
                "db" : "admin"
            }
        ]
    }
]
#再看看新建的那个用户
> db.getUser("ttt")
{
    "_id" : "admin.ttt",
    "user" : "ttt",
    "db" : "admin",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}
#我们修改用户的所有信息,都可以通过下面这条命令实现,
#db.updateUser("UESR",{修改信息})
#现在我们需要修改的是密码
> db.updateUser("ttt",{pwd:"789"})
#修改完成,旧密码登录就会报错
> db.auth("ttt","123")
Error: Authentication failed.
0
#新密码就没事了
> db.auth("ttt","789")
1
#不过,修改密码的方式并不是只有一种,下面这种也行
> db.changeUserPassword("ttt","456")
#同理,旧密码登录就会报错了
> db.auth("ttt","123")
Error: Authentication failed.
0
#新密码就没事了
> db.auth("ttt","456")
1
#删除用户就很简单了
> db.dropUser("ttt")
true
#现在你还想登录,当然是不行的
> db.getUser("ttt")
2018-07-18T09:38:38.504+0800 E QUERY    [thread1] Error: not authorized on admin to execute command { usersInfo: "ttt" } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype.getUser@src/mongo/shell/db.js:1518:1
@(shell):1:1
#登录到其他用户就行了
> db.auth("root","root123")
1
> db.dropUser("ttt")
false
> db.getUser("ttt")
null
> db.getUsers()
[
    {
        "_id" : "admin.adminuser",
        "user" : "adminuser",
        "db" : "admin",
        "roles" : [
            {
                "role" : "userAdminAnyDatabase",
                "db" : "admin"
            }
        ]
    },
    {
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
            {
                "role" : "root",
                "db" : "admin"
            }
        ]
    }
]
>

关于单台服务器的认证方式就说到这里了.


对集群数据库增加mongodb认证信息

正如我之前说的,使用mongodb,大部分人不会只用单台,因为这就是源生的分布式数据库.而使用集群的认证,比起单台,则需要增加一个keyfile,当然你也能用另一种,这里不展开讲太多.

我这里前置条件说明一下,这个时候集群是已经搭建好了,但是集群内的用户还没有创建起来,因为你没有创建keyfile也是走不起来.

首先,要在所有节点配置都打开keyfile,并配上路径,并确保mongodb有这个文件的权限,无论你是分片集群,还是单纯副本集,在mongos端,config端,share端,都要一起启用,要不然没有配置的就会报权限错误,如果是副本集而又授权了,你还需要重新做一遍才行.

#打开配置文件
vim /usr/local/mongodb/mongod_data_40001.conf
    .
    .
    .
#是否开启认证模式,现在开启来使用
auth = true
#关闭认证模式,和上面的冲突,之前是开启的,现在关闭了
#noauth = true
#指定集群认证文件,没开认证就不用指定,注释关闭即可,需要用openssl来生成,暂时不研究
keyFile  = /data/mongodb/data/keyfile
#指定访问地址,3.4之前默认全网,之后则默认是127.0.0.1,但是在3.6之后必须制定这个参数才能启动.配置0.0.0.0代表全网匹配
#bind_ip=0.0.0.0

改完之后,没启动就先不要急着启动,而已经启动了的,也不要急着重启,稍等再重启.


然后,我们要生成这个keyfile文件

#用openssl命令生成一个64位的秘钥文件
openssl rand -base64 64 > keyfile
#把它权限设成600,不然就报错权限过高的错误
chmod 600 keyfile
#把他移到目的目录
mv keyfile /data/mongodb/data/
#记得把权限搞一搞
chown mongodb:mongodb /data/mongodb/data/keyfile

有些人好奇,为什么是64位的秘钥文件?没错,真的可以更多,或者更少,例如:

openssl rand -base64 741 >keyfile
openssl rand -base64 16 >keyfile

这些都可以用,但是,要考虑系统性能问题和数据安全的问题.秘钥文件越复杂,那么你内部系统的加密与解密就需要更耗费资源,尤其在高并发环境,可以讲比较悲催.但是太简单,那么你的数据被破解的几率就更高,安全性就谈不上了.我这里只是折衷,所以是64,各位有兴趣可以根据实际情况来设置.


再然后,重新启动各节点,或者说你没启动的话,就现在启动了,按以下顺序重启所有服务
config副本集:先主库,再从库,让他慢慢切换.

router服务:随便重启.

shard副本集:先主库,再从库,让他慢慢切换.


最后,就开始创建用户授权了,就和上面一样操作就可以了

#如果我们没有做好副本集或集群,那就还需要先做,详细解析我就不做了.
> config = {_id:"sljd_shard1",members:[{_id:0, host:"172.25.40.80:40001" },{_id:1, host:"172.25.40.81:40001" },{_id:2, host:"172.25.40.82:40001" }]}
> rs.initiate(config)
> rs.status()
#然后进入admin数据库,也是当前用户认证库
shard1:PRIMARY> use admin
switched to db admin
#授权
shard1:PRIMARY> db.createUser({user:"root",pwd:"admin123",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
Successfully added user: {
    "user" : "adminuser",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}
#然后登陆
shard1:PRIMARY> db.auth("root","admin123")
#或者
mongo 172.25.40.80:40001/admin -u root -p "admin123"

然后,我们看到用户了

#登陆上主库,注意认证库
mongo 172.25.40.80:40001/admin -u root -p "admin123"
#在主库上查看一下用户情况
shard1:PRIMARY> db.getUsers()
[
    {
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
            {
                "role" : "root",
                "db" : "admin"
            }
        ]
    }
]
#登陆上从库.注意认证库
mongo 172.25.40.81:40001/admin -u root -p "admin123"
#要多做一步,允许在从库执行查询,不然会报错,因为从库默认是只读的
shard1:SECONDARY> rs.slaveOk()
#再在从库执行一下
shard1:SECONDARY> db.getUsers()
[
    {
        "_id" : "admin.root",
        "user" : "root",
        "db" : "admin",
        "roles" : [
            {
                "role" : "root",
                "db" : "admin"
            }
        ]
    }
]

好了,那就没问题了.







您可能感兴趣的文档:

--结束END--

本文标题: 建立mongodb的登录认证功能

本文链接: https://lsjlt.com/news/42181.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 建立mongodb的登录认证功能
    对于一个完善的数据库系统,必然是需要权限控制,当然mongodb也不例外.没有认证的数据库已经被证明是******的一个突破口,所以我们无论是出于什么原因,数据库认证对于一个生产系统而言,至关重要.在Mon...
    99+
    2024-04-02
  • MongoDB4.28开启权限认证配置用户密码登录功能
    目录1、查看是否开启认证登录2、开启用户名和密码认证(创建用户均需进入admin数据库)2.1、为admin数据库创建管理员账号2.2、为数据库mytest创建普通用户2.3、配置文...
    99+
    2024-04-02
  • WinForm中怎么实现登陆认证功能
    在WinForm中实现登陆认证功能的一种常用方法是使用对话框来让用户输入用户名和密码,然后与预先存储的用户名和密码进行比较来验证用户...
    99+
    2024-04-08
    winform
  • Express + Session 实现登录验证功能
    1. 写在前面 当我们登录了一个网站,在没有退出登录的情况下,我们关闭了这个网站 ,过一段时间,再次打开这个网站,依然还会是登录状态。这是因为,当我们登录了一个网站,服务器会保存我们的登录状态,直到我们退出...
    99+
    2022-06-04
    功能 Express Session
  • java实现登录验证码功能
    本文实例为大家分享了java实现登录验证码功能的具体代码,供大家参考,具体内容如下 登录验证码 登录验证是大多数登录系统都会用到的一个功能,它的验证方式也是有很多种,例如登录验证码,...
    99+
    2024-04-02
  • Java开发之spring security实现基于MongoDB的认证功能
    本文实例讲述了Java开发之spring security实现基于MongoDB的认证功能。分享给大家供大家参考,具体如下:spring security对基于数据库的认证支持仅限于JDBC,而很多项目并非使用JDBC,比如Nosql数据库...
    99+
    2023-05-30
    java spring security
  • PHP实现JWT的Token登录认证
    1、JWT简介 JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案。 session登录认证方案:用户从客户端传递用户名、密码等信息,服务端认证后将信息存储在session中,将session_id放到cookie...
    99+
    2017-03-29
    PHP实现Token登录认证 PHP Token认证 Token登录认证
  • 浅谈django中的认证与登录
    认证登录 django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1 authenticate(**credentials) 提供了用户认证,即验证用户名以及密码是否正确 ...
    99+
    2022-06-04
    浅谈 django
  • MongoDB4.28如何开启权限认证配置用户密码登录功能
    这篇文章给大家介绍MongoDB4.28如何开启权限认证配置用户密码登录功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。MongoDB默认不启用授权认证,只要能连接到该服务器,就可连接到mongod。若要启用安全认证...
    99+
    2023-06-26
  • Vue3实现登录表单验证功能
    目录一.实现思路与效果图二.实现具体过程三.完整代码与效果图一.实现思路与效果图 使用async-validator 插件,阿里出品的 antd 和 ElementUI 组件库中表单...
    99+
    2024-04-02
  • 分析xxljob登入功能集成OIDC的统一认证
    目录前言XXL-JOB自身认证功能分析OIDC的认证流程XXL-JOB集成OIDC后的认证流程XXL-JOB登录模块重新设计编码环节前言 xxl-job 是一款 java 开发的、开...
    99+
    2024-04-02
  • Security登录认证的流程是什么
    这篇文章主要介绍“Security登录认证的流程是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Security登录认证的流程是什么”文章能帮助大家解决问题。一、前言:流程图:二、前台发送请求用...
    99+
    2023-06-26
  • Hybris ECP的登录认证怎么实现
    本篇内容主要讲解“Hybris ECP的登录认证怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Hybris ECP的登录认证怎么实现”吧!Hybris ECPHybris Adminis...
    99+
    2023-06-04
  • 搭建FreeRadius实现远程登录认证(第一部分)
    Linux+FreeRadius+Mysql实现Radius认证第一部分服务器端配置一、基础系统准备1、安装Redhat-Linux操作系统,系统版本号5.52、安装Mysql所有3个组件,如下图所示:3、...
    99+
    2024-04-02
  • Node+Express+MongoDB实现登录注册功能实例
    注入MongoDB 依赖 var mongoose = require("mongoose"); 由于需要进行表单处理,需要用到bodyParser中间件 bodyParser模块来做文件解析,将表单...
    99+
    2022-06-04
    实例 功能 Node
  • Node+Express+MongoDB如何实现登录注册功能
    小编给大家分享一下Node+Express+MongoDB如何实现登录注册功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!注入MongoDB 依赖var mongoose&nb...
    99+
    2024-04-02
  • springboot整合shiro多验证登录功能的实现(账号密码登录和使用手机验证码登录)
    1. 首先新建一个shiroConfig shiro的配置类,代码如下: @Configuration public class SpringShiroConfig { ...
    99+
    2024-04-02
  • PHP如何实现JWT的Token登录认证
    本篇内容介绍了“PHP如何实现JWT的Token登录认证”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、JWT简介JSON Web Tok...
    99+
    2023-06-21
  • SpringBootsecurity安全认证登录的实现方法
    目录前言一、登录时序图二、配置与代码1.引入库2.代码文件参考文档前言 本文章主要从spring security安全认证登录内部调用流程来流程分析登录过程。 一、登录时序图 时序...
    99+
    2023-02-25
    SpringBoot security安全认证登录 SpringBoot security登录 SpringBoot安全认证登录
  • Django中使用pillow实现登录验证码功能(带刷新验证码功能)
    首先在项目里建立common目录,编写验证码的函数 verification_code.py import random from PIL import Image, Imag...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作