0%

shiro-身份认证

junit学习并总结shiro的身份认证

shiro-身份认证

介绍:

官网地址

验证主体Subject(会存入前端的账号/密码)是否存在于realm(后端数据源)中

code Implementation

demo

使用junit的shiro入门demo

  1. 新建项目

  2. 导入maven依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiaoruiit</groupId>
    <artifactId>shiro-learn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
    <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.3</version>
    </dependency>
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.2.2</version>
    </dependency>
    </dependencies>
    </project>
  3. 配置后端数据源

    resources下新建shiro.ini文件

    1
    2
    3
    [users]
    zhang=123
    wang=123

    notice:idea需要ini4idea插件,并配置。参考

  4. junit测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    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;
    import org.apache.shiro.util.ThreadContext;
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Test;

    import static org.junit.Assert.*;

    public class LoginLogout {

    @Test
    public void testHelloword (){
    //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
    //2、得到SecurityManager实例 并绑定给SecurityUtils
    SecurityManager securityManager = factory.getInstance();

    SecurityUtils.setSecurityManager(securityManager);
    //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
    Subject subject = SecurityUtils.getSubject();
    // 4.从前端传来的账号/密码
    UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
    try {
    // 身份验证
    subject.login(token);
    } catch (AuthenticationException e){
    // 认证失败
    e.printStackTrace();
    System.out.println("登录失败");
    }

    Assert.assertEquals(true, subject.isAuthenticated());// 断言用户已经登录
    // 退出,会清理session
    subject.logout();
    }

    @After
    public void close(){
    // 不执行可能影响第二次运行Test
    ThreadContext.unbindSubject();
    }
    }

Singlon-Realm

  1. 从demo的3开始

    新建MyRealm类实现Realm接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import org.apache.shiro.authc.*;
    import org.apache.shiro.realm.Realm;

    /**
    * @author hxr
    * @Classname MyRealm
    * @Description ToDo
    */
    public class MyRealm implements Realm {
    // 返回一个唯一的Realm名字
    public String getName() {
    return "myRealm";
    }

    //判断此Realm是否支持此Token
    public boolean supports(AuthenticationToken authenticationToken) {
    // 仅支持UsernamePasswordToken类型的Token
    return authenticationToken instanceof UsernamePasswordToken;
    }

    //根据Token获取认证信息
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    // 获取用户名
    String username = (String) authenticationToken.getPrincipal();
    // 获取密码
    String password = new String((char[])authenticationToken.getCredentials());

    if (!"zhang".equals(username)){
    throw new UnknownAccountException();// 用户名不存在
    }
    if (!"123".equals(password)){
    throw new IncorrectCredentialsException();// 密码错误
    }
    // 认证成功,返回AutnenticationInfo信息
    return new SimpleAuthenticationInfo(username, password, getName());
    }
    }
  2. 配置MyRealm

    resource下新建shiro-realm文件

    1
    2
    3
    4
    5
    [main]
    #声明一个realm
    myRealm = com.xiaoruiit.shiro.config.MyRealm
    #指定securityManager的realms实现
    securityManager.realms=$myRealm
  3. junit测试

    增加一个测试方法,修改shrio-reaml.ini即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Test
    public void testSingleRealm(){
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
    SecurityManager securityManager = factory.getInstance();
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
    try {
    subject.login(token);
    } catch (AuthenticationException e){
    // 认证失败
    e.printStackTrace();
    System.out.println("登录失败");
    }

    Assert.assertEquals(true, subject.isAuthenticated());// 断言用户已经登录
    subject.logout();
    }

JDBC-Realm

建立在在demo的基础上

  1. 导入数据库依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.25</version>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>0.2.23</version>
    </dependency>
  2. 在mysql中新建库shiro

  3. 新建三个表+1条user信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    drop database if exists shiro;
    create database shiro;
    use shiro;

    create table users (
    id bigint auto_increment,
    username varchar(100),
    password varchar(100),
    password_salt varchar(100),
    constraint pk_users primary key(id)
    ) charset=utf8 ENGINE=InnoDB;
    create unique index idx_users_username on users(username);

    create table user_roles(
    id bigint auto_increment,
    username varchar(100),
    role_name varchar(100),
    constraint pk_user_roles primary key(id)
    ) charset=utf8 ENGINE=InnoDB;
    create unique index idx_user_roles on user_roles(username, role_name);

    create table roles_permissions(
    id bigint auto_increment,
    role_name varchar(100),
    permission varchar(100),
    constraint pk_roles_permissions primary key(id)
    ) charset=utf8 ENGINE=InnoDB;
    create unique index idx_roles_permissions on roles_permissions(role_name, permission);

    insert into users(username,password)values('zhang','123');
  4. 配置shiro-jdbc-realm

    resource下新建shiro-jdbc-realm.ini

    1
    2
    3
    4
    5
    6
    7
    8
    9
    jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    dataSource=com.alibaba.druid.pool.DruidDataSource
    dataSource.driverClassName=com.mysql.jdbc.Driver
    dataSource.url=jdbc:mysql://localhost:3306/shiro
    dataSource.username=root
    dataSource.password=123456

    jdbcRealm.dataSource=$dataSource
    securityManager.realms=$jdbcRealm

    JdbcRealm是shrio提供的。可继承并重写方法来改写sql

  5. junit测试

    修改shiro-jdbc-realm.ini

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Test
    public void testJdbcRealm(){
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
    SecurityManager securityManager = factory.getInstance();
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
    try {
    subject.login(token);
    } catch (AuthenticationException e){
    // 认证失败
    e.printStackTrace();
    System.out.println("登录失败");
    }

    Assert.assertEquals(true, subject.isAuthenticated());// 断言用户已经登录
    subject.logout();
    }