Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 278|回复: 0

MySQL普通用户无法本地登录的解决方法及MySQL的用户认证算法

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-15 15:50:00 | 显示全部楼层 |阅读模式

    在安装完成MySQL后,我们通常添加拥有相应权限的普通用户用来访问数据库。在使用普通用户本地登录数据库的时候,经常会出现怎么登录也无法登录的情况。

    例如,我的MySQL中的用户为:

    mysql> SELECT User, Host, Password FROM mysql.user;
    +------+------------------+-------------------------------------------+
    | User | Host             | Password                                  |
    +------+------------------+-------------------------------------------+
    | root | localhost        | *84BB5DF4823DA319BBF86C99624479A198E6EEE9 |
    | root | liao.localdomain | *84BB5DF4823DA319BBF86C99624479A198E6EEE9 |
    | root | 127.0.0.1        | *84BB5DF4823DA319BBF86C99624479A198E6EEE9 |
    | GaMe | %                | *84BB5DF4823DA319BBF86C99624479A198E6EEE9 |
    | root | %                | *84BB5DF4823DA319BBF86C99624479A198E6EEE9 |
    |      | localhost        |                                           |
    |      | liao.localdomain |                                           |
    +------+------------------+-------------------------------------------+

     

     可以看到,我的数据库中有root用户,GaMe用户和匿名用户,GaMe用户的主机使用%代表所有主机。

    GaMe用户的密码是'redhat', 匿名用户的密码为空

     

    在本机使用GaMe账户登录数据库:

    [root@liao ~]# mysql -uGaMe -p'redhat'
    ERROR 1045 (28000): Access denied for user 'GaMe'@'localhost' (using password: YES)
    [root@liao ~]# mysql -uGaMe -p'redhat'
    ERROR 1045 (28000): Access denied for user 'GaMe'@'localhost' (using password: YES)

     

    结果是无论如何都提示登录被拒绝。

    再次使用GaMe账户登录数据库,这次我使用空密码尝试

    [root@liao ~]# mysql -uGaMe -p
    Enter password: 
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 59
    Server version: 5.5.21-log Source distribution
    
    Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql> 

     

    登录成功了,使用USER()和CURRENT_USER()两个函数查看所使用的用户。

    USER()函数返回你在客户端登陆时指定的用户名和主机名。

    CURRENT_USER()函数返回的是MySQL使用授权表中的哪个用户来认证你的登录请求。

    mysql> SELECT USER(), CURRENT_USER();
    +----------------+----------------+
    | USER()         | CURRENT_USER() |
    +----------------+----------------+
    | GaMe@localhost | @localhost     |
    +----------------+----------------+
    1 row in set (0.00 sec)

     

    这里发现,我使用'GaMe'@'localhost'这个账户登录数据库(因为在本地登陆时没指定主机,默认是以localhost登录),但是数据库使用的是''@'localhost'这个账户来进行登录认证,而''@'localhost'这个匿名用户是没有密码的,因此我输入空密码登录成功了。但是登录后,所对应的用户的匿名用户。

    一般在MySQL在安装完毕后,我们使用mysql_install_db这个脚本生成授权表,会默认创建''@'localhost'这个匿名用户。正是因为这个匿名用户,影响了其他用户从本地登录的认证。

     

    那么MySQL是如何进行用户身份认证呢?

     

    通过Google查的资料,总结MySQL的简要认证算法如下:

    • 当用户从客户端请求登陆时,MySQL将授权表中的条目与客户端所提供的条目进行比较,包括用户的用户名,密码和主机。
    • 授权表中的Host字段是可以使用通配符作为模式进行匹配的,如test.example.com, %.example.com, %.com和%都可以匹配test.example.com这个主机。
    • 授权表中的User字段不允许使用模式匹配,但是可以有一个空字符的用户名代表匿名用户,并且空字符串可以匹配所有的用户名,就像通配符一样。
    • 当user表中的Host和User有多个值可以匹配客户端提供的主机和用户名时,MySQL将user表读入内存,并且按照一定规则排序,按照排序规则读取到的第一个匹配客户端用户名和主机名的条目对客户端进行身份验证。

     

    排序规则:

    • 对于Host字段,按照匹配的精确程度进行排序,越精确的排序越前,例如当匹配test.example.com这个主机时, %.example.com%.com更精确,而test.example.com%.example.com更精确。
    • 对于User字段,非空的字符串用户名比空字符串匹配的用户名排序更靠前。
    • User和Host字段都有多个匹配值,MySQL使用主机名排序最前的条目,在主机名字段相同时再选取用户名排序更前的条目。
    • 因此,如果User和Host字段都有多个匹配值,主机名最精确匹配的条目被用户对用户进行认证。

     

    了解了这个认证流程,就知道为什么GaMe登录失败了。

    使用GaMe在本机登录数据时,不指定-h参数默认为localhost主机登录,而在MySQL中有两个匹配的条目:

    1. 'GaMe'@'%'
    2. ''@'localhost'

    匿名用户能够匹配的原因上面说过,空字符串可以匹配所有的用户名,就像通配符一样。

    根据MySQL认证时的排序规则,第一个条目的用户名排序更前,第二个条目的主机名更精确,排序更前。

    而MySQL会优先使用主机名排序第一的条目进行身份认证,因此''@'localhost'被用户对客户端进行认证。因此,只有使用匿名用户的空密码才能登录进数据库。就会出现下面的情况了。

    mysql> SELECT USER(), CURRENT_USER();
    +----------------+----------------+
    | USER()         | CURRENT_USER() |
    +----------------+----------------+
    | GaMe@localhost | @localhost     |
    +----------------+----------------+
    1 row in set (0.00 sec)

     

    解决的方法:删除匿名用户(仅仅为了安全也有这个必要)

     

    为什么root用户不会受影响,而只有普通用户不能从本地登录?

    因为mysql_install_db脚本会在授权表中生成'root'@'localhost'这个账户。同样的,使用root登录MySQL时,'root'@'localhost'和''@'localhost'都能匹配登录的账户,但是根据排序规则,主机名相同,而用户名非空字符串优先,因此'roo'@'localhost'这个条目的排序更靠前。使用root本地登录是不会被匿名用户遮盖。

     

     

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-16 21:13 , Processed in 0.070274 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表