第一个Shiro程序

Shiro 简介

什么是Shiro

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证,授权、密码学和会话管理。

Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
Authorization:授权,即验证权限,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限。
Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通的JavaSE环境的,也可以是Web环境的。
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web支持,可以非常容易的集成到Web环境中
Caching:缓存,比如用户登录后,其用户信息,拥有的角色/权限不必每次去查,提高效率。
Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
Rember Me:记住我,这是非常常见的功能,即一次登录后,下次再来的话不用登录了。

主要功能

身份验证、授权、加密、会话

身份认证

流程如下:
1、首先调用 Subject.login(token)进行登录,其会自动委托给 Security Manager,调用之前必
须通过 SecurityUtils. setSecurityManager()设置;
2、SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
3、Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自
定义插入自己的实现;
4、Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认
ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
5、Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返
回/抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进
行访问。

Shiro 第一个小程序

  • 添加jar包
<!---shiro 架包 -->

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
</dependency>

<!---日记jar包 使用shiro需要使用这jar包 -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
</dependency>

<!---数据库 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>

<!-- 日志 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
</dependency>


  • 配置核心文件
    Shiro 使用的ini文件当做配置文件
    shiro.ini
#定义用户信息,用户名,或者密码
[users]
admin=123
tom=456

测试

public static void main(String[] args) {

 //第一步 获取Security Manager ,指定配置文件初始化
 IniSecurityManagerFactory factory= new IniSecurityManagerFactory("classpath:shiro01/shiro01.ini");
 SecurityManager securityManager = factory.getInstance();

  //第二步 对SecurityManager进行封装,委托给SecurityUtils

 SecurityUtils.setSecurityManager(securityManager);

 //第三步获取用户主体 Subject

org.apache.shiro.subject.Subject subject=SecurityUtils.getSubject();
 //第四步登录
 UsernamePasswordToken token=new UsernamePasswordToken("admin","123");

 //第五步 身份认证 认证成功返回true,认证失败抛出异常
 try {
     //认证前
      // System.out.println("认证之前-是否认证:"+subject.isAuthenticated());
     subject.login(token);
      // System.out.println("认证之后-是否认证:"+subject.isAuthenticated());
     //  System.out.println("调用logout");
     //  subject.logout();
   //  System.out.println("是否认证:"+subject.isAuthenticated());
 } catch (UnknownAccountException e) {
       System.out.println("账户异常:"+e.getMessage());
 }catch (IncorrectCredentialsException e)
 {
     System.out.println("密码异常:"+e.getMessage());
 }
}

Shiro 默认配置

在ini核心配置文件中有如下默认配置,SecurityManager、Authenticator 、Authentication、Realm

#定义用户信息,用户名,或者密码
[users]
admin=123
tom=456


#以下默认可以省略#

#默认的SecurityManager
##相当于spring容器中定义的bean securityManager 为id  org.apache.shiro.mgt.DefaultSecurityManager 是对应的bean 实现类
 securityManager=org.apache.shiro.mgt.DefaultSecurityManager

 # 默认认证器
 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
 #将认证器添加到SecurityManager中
securityManager.authentication=$authenticator

# 默认的认证策略
authenticationStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
#将认证策略添加到认证器中,相当于注入操作,要以$开头
authenticator.authenticationStrategy=$authenticationStrategy


#默认的Realm
iniRealm=org.apache.shiro.realm.text.IniRealm
#将Realm添加到SecurityManager中
securitymanager.realms=$iniRealm

Realm 介绍

Realm :安全数据源,也就是数据放哪里。

默认有三种:

  • iniRealm :数据放到ini文件里面
  • JdbcRealm:数据放到数据库里面
  • PropertiesRealm 数据放到Properties文件里面
    iniRealm 使用:
    见第一个shiro例子
    JdbcRealm 使用:
  • 导包
  • 建表
drop database if exists shiro;
create database shiro  charset utf8 ;
use shiro;
create table t_user
(
id int primary key auto_increment,
login_name varchar(200) not null  unique,
password varchar(200)
)engine=Innodb charset utf8;

insert  into t_user(login_name,password)values('admin','111');
insert into t_user(login_name,password)values('tom','222');
  • 工具类

public class ShiroUtils {


    public static Subject getSubject(String iniPath) {
        //第一步 获取Security Manager ,指定配置文件初始化
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory(iniPath);
        org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();

        // 第二步 对SecurityManager进行封装委托给SecurityUtils

        SecurityUtils.setSecurityManager(securityManager);

        //第三步获取用户主体 Subject

        org.apache.shiro.subject.Subject subject = SecurityUtils.getSubject();
        return subject;
    }
}
  • 日志文件
log4j.rootLogger=info,hello
log4j.appender.hello=org.apache.log4j.ConsoleAppender
log4j.appender.hello.layout=org.apache.log4j.SimpleLayout
  • ini配置文件

#配置数据源

dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro?useUnicde=false&characterEncoding=utf-8
dataSource.username=root
dataSource.password=123456

# 使用JdbcRealm

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#注入数据源
jdbcRealm.dataSource=$dataSource
#默认sql语句
#    protected static final java.lang.String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
#   protected String authenticationQuery = DEFAULT_AUTHENTICATION_QUERY;
# public void setAuthenticationQuery(String authenticationQuery) {  this.authenticationQuery = authenticationQuery;  }
#重写认证sql语句
jdbcRealm.authenticationQuery=select password from t_user where login_name=?

# 将JdbcRealm 添加到SecurityManager
#securityManager  是默认名   securityManager=org.apache.shiro.mgt.DefaultSecurityManager

securityManager.realms=$jdbcRealm

  • 测试

public static void main(String[] args) {

 Subject subject= ShiroUtils.getSubject("classpath:shiro02/shiro.ini");

    UsernamePasswordToken token=new UsernamePasswordToken("admin","111");
    try {
        //认证前
         // System.out.println("认证之前-是否认证:"+subject.isAuthenticated());
        subject.login(token);
         // System.out.println("认证之后-是否认证:"+subject.isAuthenticated());
        //  System.out.println("调用logout");
        //  subject.logout();
     System.out.println("是否认证:"+subject.isAuthenticated());
    } catch (UnknownAccountException e) {
          System.out.println("账户异常:"+e.getMessage());
    }catch (IncorrectCredentialsException e)
    {
        System.out.println("密码异常:"+e.getMessage());
    }catch (AuthenticationException e){

          System.out.println(e.getMessage());
    }

}

自定义Realm

如果使用的是QQ、微信等登陆方式,则需要自定义Realm

步骤

  • 定义一个类,继承 AuthorizingRealm

public class PropertiesRealm extends AuthorizingRealm {

    private String path;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    /*
        *
        * 授权
        * */
    @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    /*
    *  身份的验证
    * */
    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {

        //获取token中的用户名

        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        String username = usernamePasswordToken.getUsername();

        //查找数据源

        Properties p = new Properties();
        try {

            if (path.startsWith("classpath:")) {

                path = path.substring(10);
                p.load(PropertiesRealm.class.getClassLoader().getResourceAsStream(path));

            } else if (path.startsWith("file:")) {
                p.load(new FileInputStream(path));
            }
        } catch (IOException ex) {
            ex.printStackTrace();

        }
        String password=p.getProperty("user."+username);

        if(password!=null)
        {

              AuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(
                      username,//用户名
                      password,//数据源中真的真是密码
                      getName()//Reaml 名称
              );
            return authenticationInfo;

        }

        return null;

}
}

  • 配置文件


# 使用自定义Reaml

propertiesRealm= shiro02.realm.PropertiesRealm
propertiesRealm.path=classpath:shiro02/user.properties


# 将JdbcRealm 添加到SecurityManager
#securityManager  是默认名   securityManager=org.apache.shiro.mgt.DefaultSecurityManager


securityManager.realms=$propertiesRealm

*属性文件


user.admin=11
user.tom=666

原文地址:https://www.cnblogs.com/lilihai/p/10142108.html