03-2 shiro身份验证

03-2 shiro身份验证

  • 在shiro中用户需要提供身份(principals)和证明(credentials)给shiro。从而应用可以验证用户身份。
  • principals:身份,主体的标识属性(用户名)
  • credentials:证明/凭证,只有主体知道的安全值(密码)
  • Subject:主体
  • Realm:数据源
本篇内容:
  • 1、通过ini身份验证
  • 2、身份验证流程
  • 3、使用realm身份验证
  • 4、使用多个realm身份验证
  • 5、使用数据库身份验证
本篇demo项目结构
01-check
    |---01-check-demo
    |---02-check-realm
    |---03-check-realm-more
    |---04-check-jdbc

一、环境搭建

  • 采用maven的方式创建

1、添加pom依赖

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</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>

二、简单使用身份验证:

2.1、创建项目:01-check-demo

2.2、创建用户身份和凭证文件:shiro.ini

  • 文件路径:在resource文件夹中
[users]
zhang=123
wang=123

2.3、身份校验

package com.check;
import org.apache.shiro.SecurityUtils;
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.junit.Test;
/**
 * @author brusion
 * @date 2018/9/15
 */
public class ShiroApplication {
    @Test
    public void shiroTest() {
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager manager = factory.getInstance();
        SecurityUtils.setSecurityManager(manager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            subject.login(token);
            System.out.println("=== 登录成功 === ");
        } catch (Exception e) {
            System.out.println("=== 登录失败 === ");
        }
        subject.logout();
    }
}

2.4、测试结果

--- 登录成功 ---

2.5、API说明

2.5.1、Factory工厂类
Factory
|---JndiObjectFactory
|---AbstractFactory
    |---IniFactorySupport
        |---IniSecurityManagerFactory
2.5.2、SecurityManager接口对象
interface SecurityManager extends Authenticator, Authorizer, SessionManager {
    Subject login(Subject var1, AuthenticationToken var2) throws AuthenticationException;
    void logout(Subject var1);
    Subject createSubject(SubjectContext var1);
}
2.5.3、SecurityUtils工具类
public abstract class SecurityUtils {
    private static SecurityManager securityManager;
    public SecurityUtils() ;
    public static Subject getSubject();
    public static void setSecurityManager(SecurityManager securityManager);
    public static SecurityManager getSecurityManager();
}
2.5.4、UsernamePasswordToken
Serializable
    |---AuthenticationToken
        |---HostAuthenticationToken
            |---UsernamePasswordToken
        |---RememberMeAuthenticationToken
            |---UsernamePasswordToken

三、shiro的身份认证流程

  • 1、调用Subject#login(token)进行登录,会自动委托给Security Manager。(调用前需要设置SecurityManager)
  • 2、SecurityManager负责身份验证逻辑,并委托给Authenticator进行身份验证(Authenticator是真正的身份验证者)
  • 3、Authenticator会委托给相应的AuthenticationStrategy进行多Realm身份验证。(默认ModularRealmAuthenticator会调用AuthenticatorStrategy进行Realm身份验证)
  • 4、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息。如果没有对应信息则抛出异常。

四、使用realm作为数据源

1、创建自定义Realm

  • 理解为将用户的账号和密码没有用ini文件的方式,而是采用自定义realm方式配置数据
package com.check;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;
/**
 * @author brusion
 * @date 2018/9/15
 */
public class SingleRealm implements Realm {
    @Override
    public String getName() {
        return getClass().getName();
    }
    @Override
    public boolean supports(AuthenticationToken token) {
        //只支持UsernamePasswordToken类型的token
        return token instanceof UsernamePasswordToken;
    }
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户名和密码
        String name = (String) token.getPrincipal();
        String pwd = new String((char[]) token.getCredentials());
        if (!"zhang".equals(name)) {
            throw new UnknownAccountException("账号不存在..");
        }
        if (!"123".equals(pwd)) {
            throw new IncorrectCredentialsException("密码错误...");
        }
        //身份校验成功返回AuthenticationInfo实现类
        return new SimpleAuthenticationInfo(name, pwd, getName());
    }
}

2、创建配置文件:shiro_realm.ini

  • 文件路径:resource
myRealm=com.check.SingleRealm
securityManager.realms=$myRealm
说明:
  • myRealm=com.check.SingleRealm:声明自定义realm
  • securityManager.realms=$myRealm:指定SecurityManager的Realm实现类

3、身份校验

package com.check;
import org.apache.shiro.SecurityUtils;
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.junit.Test;
/**
 * @author brusion
 * @date 2018/9/15
 */
public class RealmApplication {
    @Test
    public void realmTest(){
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro_realm.ini");
        SecurityManager manager = factory.getInstance();
        SecurityUtils.setSecurityManager(manager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");
        try {
            subject.login(token);
            System.out.println("=== 登录成功 === ");
        } catch (Exception e) {
            System.out.println("=== 登录失败 === ");
        }
        subject.logout();
    }
}

4、测试结果

=== 登录成功 === 

五、多个realm方式数据配置

1、创建项目:03-check-realm-more

2、创建自定义Realm类 realm1

package com.check.realm;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;
/**
 * @author brusion
 * @date 2018/9/15
 */
public class Realm1 implements Realm {
    @Override
    public String getName() {
        return getClass().getName();
    }
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String name = (String) token.getPrincipal();
        String pwd = new String((char[]) token.getCredentials());
        if (!"zhang".equals(name)) {
            throw new UnknownAccountException("账号错误");
        }
        if (!"123".equals(pwd)) {
            throw new IncorrectCredentialsException("密码错误");
        }
        return new SimpleAuthenticationInfo(name, pwd, getName());
    }
}

3、自定义realm类realm2

package com.check.realm;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;
/**
 * @author brusion
 * @date 2018/9/15
 */
public class Realm2 implements Realm {
    @Override
    public String getName() {
        return getClass().getName();
    }
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String name = (String) token.getPrincipal();
        String pwd = new String((char[]) token.getCredentials());
        if (!"san".equals(name)) {
            throw new UnknownAccountException("账号错误");
        }
        if (!"456".equals(pwd)) {
            throw new IncorrectCredentialsException("密码错误");
        }
        return new SimpleAuthenticationInfo(name, pwd, getName());
    }
}

4、创建配置文件:shiro_more_realm.ini

  • 文件地址路径:放在resource下
myRealm1= com.check.realm.Realm1
myRealm2= com.check.realm.Realm2
securityManager.realms=$myRealm1,$myRealm2

5、验证身份

package com.check;
import org.apache.shiro.SecurityUtils;
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.junit.Test;
/**
 * 多个realm数据源
 *
 * @author brusion
 * @date 2018/9/15
 */
public class MoreRealmApplication {
    @Test
    public void moreRealmTest() {
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro_more_realm.ini");
        SecurityManager manager = factory.getInstance();
        SecurityUtils.setSecurityManager(manager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("san", "456");
        try {
            subject.login(token);
            System.out.println("== 登录成功 ===");
        } catch (Exception e) {
            System.out.println("== 登录失败 ===");
        }
        subject.logout();
    }
}

6、测试运行

== 登录成功 ===

六、从数据库中获取数据源

  • 前面几个demo中的数据都是从ini文件或者realm中获取,实际项目中数据都是从数据库中获取
  • 本案例采用jdbc方式连接获取数据库中数据并进行数据校验

1、数据库表创建

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');

2、项目创建:04-check-jdbc

3、pom中添加数据库连接库配置

 <dependencies>
        <!--数据库连接池-->
        <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>
    </dependencies>

4、创建配置文件

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=123123
jdbcRealm.dataSource=$dataSource
securityManager.realms=$jdbcRealm

5、身份验证

package com.check;
import org.apache.shiro.SecurityUtils;
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.junit.Test;
/**
 * @author brusion
 * @date 2018/9/15
 */
public class JDBCApplication {
    @Test
    public void jdbcTest(){
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro_jdbc_realm.ini");
        SecurityManager manager = factory.getInstance();
        SecurityUtils.setSecurityManager(manager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
        try {
            subject.login(token);
            System.out.println("== 登录成功 ===");
        } catch (Exception e) {
            System.out.println("== 登录失败 ===");
        }
        subject.logout();
    }
}

6、运行测试

== 登录成功 ===
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值