Shiro的Jdbc配置和验证策略(二)上

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Shiro的Jdbc配置和验证策略(二)

一. Shiro 的认证错误


在上一章节的例子中,我们可以看到, Shiro 是通用 Subject 对象的 login() 方法,进行认证判断的。 我们自己在开发中,常常有这么一个需求,在登录时,如果登录失败,会给出一些相应的提示,如用户名不存在,密码错误,账号不可用等信息。 Shiro 也提供了相应的功能。


public abstract void login(AuthenticationToken paramAuthenticationToken)
  throws AuthenticationException;


Shiro 会抛出一个异常, AuthenticationException。


这个异常有许多子类,


20200512120844398.png


通常会捕获相应的子类异常信息,进行相应的错误提示。


image.png


常见的是 IncorrectCredentialsException 密码不正确和 UnknownAccountException 和未知账户。


友情提示: 在错误信息提示时,不要提示,用户名不存在,密码错误 这样的信息,而应该是 用户名/密码 错误,避免有心人尝试密码破解或者获取网站的用户名。


登录成功之后,也可以进行相应的退出, 调用 subject对象的 logout() 方法进行退出。


写一个 用户名密码和 退出的小例子。(配置文件,仍然使用 shiro.ini)


package com.yjl.demo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
/**
 * 
 * @author 两个蝴蝶飞
 * Shiro 的第二个演示文件, 凭证错误和退出
 */
public class ShiroDemo2 {
  public static void main(String[] args) {
    //1. 创建工厂 
    Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
    //2. 从工厂里面获取 SecurityManager
    SecurityManager securityManager=factory.getInstance();
    //3. 通过工具类设置 securityManager
    SecurityUtils.setSecurityManager(securityManager);
    //4. 获取当前登录的用户
    Subject subject=SecurityUtils.getSubject();
    //5. 拼装用户的身份和密码Token
    UsernamePasswordToken token=new UsernamePasswordToken("yuezl","1234"); //1.正确密码
    //UsernamePasswordToken token=new UsernamePasswordToken("yuezl","123456"); //2.错误密码
    //UsernamePasswordToken token=new UsernamePasswordToken("yuezlAbc","1234"); //3.未知账户
    System.out.println("用户是否登录成功A:"+subject.isAuthenticated());
    //6. 调用 subject 里面的login 方法,进行登录
    try{      
      subject.login(token);
      //7.判断用户是否登录成功
      if(subject.isAuthenticated()){
        System.out.println("用户:"+token.getUsername()+", 登录成功");
      }
    }catch (UnknownAccountException var6) {
            var6.printStackTrace();
            System.out.println("没有此账号");
        } catch (IncorrectCredentialsException var7) {
            var7.printStackTrace();
            System.out.println("密码不正确");
        } catch (DisabledAccountException var8) {
            var8.printStackTrace();
            System.out.println("账户不可用");
        }
    System.out.println("用户是否登录成功B:"+subject.isAuthenticated());
    //退出程序
    subject.logout();
    System.out.println("用户是否登录成功C:"+subject.isAuthenticated());
  }
}


当运行1时, 用户名和密码均正确时:


20200512120855910.png


当运行2时,用户名正确,但密码不正确


20200512120900683.png


当运行3时,用户名不存在


20200512120907569.png


用户名和密码是我们自己在配置文件 shiro.ini 里面配置的,能不能在数据库里面查询呢?


是可以的,我们可以实现 JdbcRealm


二. 配置JdbcRealm


二.一 JdbcRealm 内置 sql语句


public class JdbcRealm
   extends AuthorizingRealm
 {
   protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password 
from users where username = ?";
  protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt 
from users where username = ?";
   protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name 
from user_roles where username = ?";
  protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission 
from roles_permissions where role_name = ?";
  private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class);
 ...
};


JdbcRealm 继承了 AuthorizingRealm 抽象类。


20200512120927291.png


由于 JdbcRealm 提供了内置的 sql 语句,所以如果我们想使用 JdbcRealm 那么就必须保证 用户表的表名必须为 users, 用户名必须为 username, 密码必须为 password 字段。 users 表不一定只有这两个字段,但必须要保证有这两个字段,如果想加盐加密,还需要有password_salt 字段。


二.二 创建数据库 shiro,用户表为 users


users 表里面必须有 username 和password 两个字段。


20200512120933394.png


二.三 添加数据库和c3p0的相应依赖


pom.xml 中追加依赖


<dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.4</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.25</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
    </dependency>


二.四 创建jdbcRealm.ini, 里面配置数据库的相应信息


不用自定义用户信息了,直接通过 JdbcRealm 从数据库里面查询。 添加一个c3p0的数据库连接池。


[main]
#配置数据源
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
#配置数据库的信息
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8
dataSource.user=root
dataSource.password=abc123
#配置 realm,用JdbcRealm
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#配置数据源
jdbcRealm.dataSource=$dataSource
#注入到securityManager里面
securityManager.realm=$jdbcRealm
#不用自定义配置users 的信息


需要在 [main] 里面进行配置, 类似于 Spring 的 注入。


二.五 测试验证


package com.yjl.demo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
/**
 * 
 * @author 两个蝴蝶飞
 * Shiro 的第三个演示文件, JdbcRealm的使用
 */
public class ShiroDemo3 {
  public static void main(String[] args) {
    //1. 创建工厂 
    Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:jdbcRealm.ini");
    //2. 从工厂里面获取 SecurityManager
    SecurityManager securityManager=factory.getInstance();
    //3. 通过工具类设置 securityManager
    SecurityUtils.setSecurityManager(securityManager);
    //4. 获取当前登录的用户
    Subject subject=SecurityUtils.getSubject();
    //5. 拼装用户的身份和密码Token
    UsernamePasswordToken token=new UsernamePasswordToken("yuezl","1234"); //1.正确密码
    //UsernamePasswordToken token=new UsernamePasswordToken("yuezl","123456"); //2.错误密码
    //UsernamePasswordToken token=new UsernamePasswordToken("yuezlAbc","1234"); //3.未知账户
    System.out.println("用户是否登录成功A:"+subject.isAuthenticated());
    //6. 调用 subject 里面的login 方法,进行登录
    try{      
      subject.login(token);
      //7.判断用户是否登录成功
      if(subject.isAuthenticated()){
        System.out.println("用户:"+token.getUsername()+", 登录成功");
      }
    }catch (UnknownAccountException var6) {
            var6.printStackTrace();
            System.out.println("没有此账号");
        } catch (IncorrectCredentialsException var7) {
            var7.printStackTrace();
            System.out.println("密码不正确");
        } catch (DisabledAccountException var8) {
            var8.printStackTrace();
            System.out.println("账户不可用");
        }
    System.out.println("用户是否登录成功B:"+subject.isAuthenticated());
    //退出程序
    subject.logout();
    System.out.println("用户是否登录成功C:"+subject.isAuthenticated());
  }
}


当运行1时, 用户名和密码均正确时:


20200512120855910.png


当运行2时,用户名正确,但密码不正确


20200512120900683.png


当运行3时,用户名不存在


20200512120907569.png


注意,数据是从数据库里面查询出来的,并不是从 jdbcRealm.ini 里面配置出来的。


一定要保证字段是一致的,不然无法通过认证。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
8月前
|
SQL Java 数据库连接
jdbc的执行流程|不同数据库的驱动配置
jdbc的执行流程|不同数据库的驱动配置
|
9月前
|
XML Java 数据库连接
java202304java学习笔记第六十五天-ssm-声明式控制-基于xml的声明式配置-原始jdbc操作1
java202304java学习笔记第六十五天-ssm-声明式控制-基于xml的声明式配置-原始jdbc操作1
44 0
|
4月前
|
前端开发 Java BI
Servlet+Jsp+JDBC实现房屋租赁管理系统(源码+数据库+论文+系统详细配置指导+ppt)
Servlet+Jsp+JDBC实现房屋租赁管理系统(源码+数据库+论文+系统详细配置指导+ppt)
|
5月前
|
Java 数据库连接 数据库
Flink全托管,holo 库同步到另一个库,报错failed to get user from ak 亲,请问是哪种权限缺失?Flink 配置中使用的是holo. jdbc 的user和password 。
Flink全托管,holo 库同步到另一个库,报错failed to get user from ak 亲,请问是哪种权限缺失?Flink 配置中使用的是holo. jdbc 的user和password 。
42 1
|
5月前
|
Java 关系型数据库 MySQL
|
8月前
|
SQL 算法 Java
Myqsql使用Sharding-JDBC配置详解3
Myqsql使用Sharding-JDBC配置详解3
67 0
|
8月前
|
SQL 算法 Java
Myqsql使用Sharding-JDBC配置详解2
Myqsql使用Sharding-JDBC配置详解2
126 0
|
8月前
|
SQL 监控 算法
Myqsql使用Sharding-JDBC配置详解1
Myqsql使用Sharding-JDBC配置详解1
46 0
|
9月前
|
XML Java 数据库连接
java202304java学习笔记第六十五天-ssm-声明式控制-基于xml的声明式配置-原始jdbc操作2
java202304java学习笔记第六十五天-ssm-声明式控制-基于xml的声明式配置-原始jdbc操作2
51 0
|
10月前
|
SQL 算法 Java
springboot中sharding jdbc绑定表配置实战
springboot中sharding jdbc绑定表配置实战