Shiro框架入门+ssm的整合

一、Shiro简介

  1. Shiro框架

在这里插入图片描述

应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject

在这里插入图片描述

  1. Shiro内部结构图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 常见单词说明
    在这里插入图片描述
  3. Shiro中的Shiro.ini说明
    在这里插入图片描述

(1) main
提供了对根对象securityManager及其依赖对象的配置

#创建对象
securityManager=org.apache.shiro.mgt.DefaultSecurityManager 

其构造器必须是public空参构造器,通过反射创建相应的实例。
1.对象名=全限定类名 相当于调用public无参构造器创建对象
2.对象名.属性名=值 相当于调用于setter方法设置常量值
3.对象名.属性名=$对象引用 相当于调用setter方法设置对象引用

(2)users
提供了对用户/密码及其角色的配置,用户名=密码,角色1,角色2
username=password,role1,role2
  例如:配置用户名/密码及其角色,格式:“用户名=密码,角色1,角色2”,角色部分可省略。如:

[users] 
zhang=123,role1,role2 
wang=123 

(3)roles
提供了角色及权限之间关系的配置,角色=权限1,权限2 role1 = permission1 , permission2
  例如:配置角色及权限之间的关系,格式:“角色=权限1,权限2”;如:

[roles] 
role1=user:create,user:update 
role2=* 

(4)urls
用于web,提供了对web url拦截相关的配置,url=拦截器[参数],拦截器

/index.html = anon 
/admin/** = authc, roles[admin],perms["permission1"]
  1. 源码分析
    在这里插入图片描述

认证使用的是 SimpleAccountRealm
在这里插入图片描述

二、在开始操作之前 不妨先导入log日志

  1. maven导包
 <!--slf-->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.30</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.30</version>
    </dependency>
  1. 在resources目录下新键log4j.properties文件
# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置   【这里面写自己的地址】  
log4j.logger.com.luo=TRACE   
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

三、第一个Shiro程序

  1. 导入shiro核心包
    <!--shiro-->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.4.0</version>
    </dependency>

  1. 在resources目录下创建一个shiro.ini文件
[users]    
xiaohu=123   
xiaoluo=456
  1. 我的测试类
public class TestAuthenticator {
    public static void main(String[] args) {
        //1.创建安全管理器的对象
//        SecurityManager securityManager = new DefaultSecurityManager();
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //2.给安全管理器设置realm
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
        //3.SecurityUtils全局安全工具类
        SecurityUtils.setSecurityManager(securityManager);
        //4.关键对象 Subject 主体
        Subject subject=SecurityUtils.getSubject();
        //5. 创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("xiaohu","1223");
        try {
            subject.login(token);//用户认证
            System.out.println("认证状态:" + subject.isAuthenticated());
        } catch (UnknownAccountException Un){
            Un.printStackTrace();
            System.out.println("认证失败:用户名错误!!");
        }catch (IncorrectCredentialsException In){
            In.printStackTrace();
            System.out.println("认证失败:密码错误!!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

四、自定义Realm(认证)

在这里插入图片描述

  1. 认证部分
//自定义的Realm实现  将认证/授权的数据的来源转为数据库的实现
public class CustomerRealm  extends AuthorizingRealm {
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //在Token获取用户名
        String principal = (String) authenticationToken.getPrincipal();
        System.out.println(principal);
        //根据身份信息,在数据库中使用  jdbc . mybatis查询相关的数据库   这里为了方便使用假的数据
        if("xiaoluo".equals(principal)){
            //  参数1:返回数据库中正确的用户名  参数2:返回数据库中正确的密码 参数3:提供当前Realm的名字 this.getName
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,"123",this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

  1. 测试代码
//自定义realm
public class TestCustomerRealmAuthenticator {
    public static void main(String[] args) {
        //1.创建安全管理器的对象
        // SecurityManager securityManager = new DefaultSecurityManager();
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //2.给安全管理器设置realm  不使用shiro.ini  使用自定义的Realm
        securityManager.setRealm(new CustomerRealm());
        //3.SecurityUtils全局安全工具类
        SecurityUtils.setSecurityManager(securityManager);
        //4.关键对象 Subject 主体
        Subject subject=SecurityUtils.getSubject();
        //5. 创建令牌luo
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoluo","123");
        try {
            subject.login(token);//用户认证
            System.out.println("认证状态:" + subject.isAuthenticated());
        } catch (UnknownAccountException Un){
            Un.printStackTrace();
            System.out.println("认证失败:用户名错误!!");
        }catch (IncorrectCredentialsException In){
            In.printStackTrace();
            System.out.println("认证失败:密码错误!!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

五、MD5+salt+hash散列在Shiro中的应用

手动获取自己密码的加密后的字符串

// 参数1:密码  参数2:盐值  参数3:hash散列次数
 Md5Hash md5Hash1 = new Md5Hash("123", "XO*7ps", 1024);
        System.out.println(md5Hash1.toHex());
  1. 自定义的Realm
//使用自定义realm加入 md5+ salt +hash
public class CustomerMD5Realm extends AuthorizingRealm {
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       return null;
   }

   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       //在Token获取用户名
       String principal = (String) authenticationToken.getPrincipal();
       //根据身份信息,在数据库中使用  jdbc . mybatis查询相关的数据库   这里为了方便使用假的数据
       if("xiaoluo".equals(principal)){
           //  参数1:返回数据库中正确的用户名  参数2:返回数据库中正确的密码经过 md5和随机盐加密之后的字符串  参数3:随机盐(可以用uuid替换) 参数4:提供当前Realm的名字 this.getName
           SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                   principal,"908da6d8e6057542323d9f58de42f9ab", ByteSource.Util.bytes("XO*7ps"),this.getName());
           return simpleAuthenticationInfo;
       }
       return null;
   }
}
  1. 测试类
public class TestCustomerMd5RealmAuthenicator {
   public static void main(String[] args) {
       //创建安全管理器
       DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
       //注入Realm
       CustomerMD5Realm realm = new CustomerMD5Realm();
       //设置realm使用hash凭证匹配器
       HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
       hashedCredentialsMatcher.setHashAlgorithmName("md5");//使用md5加密
       hashedCredentialsMatcher.setHashIterations(1024);//hash散列次数
       realm.setCredentialsMatcher(hashedCredentialsMatcher);
       defaultSecurityManager.setRealm(realm);
       //将安全管理器注入安全工具
       SecurityUtils.setSecurityManager(defaultSecurityManager);
       //通过安全工具类获取subject
       Subject subject = SecurityUtils.getSubject();

       //认证
       UsernamePasswordToken token = new UsernamePasswordToken("xiaoluo","123");
       try {
           subject.login(token);//用户认证
           System.out.println("认证状态:" + subject.isAuthenticated());
           System.out.println("登录成功");
       } catch (UnknownAccountException Un){
           Un.printStackTrace();
           System.out.println("认证失败:用户名错误!!");
       }catch (IncorrectCredentialsException In){
           In.printStackTrace();
           System.out.println("认证失败:密码错误!!");
       }catch (Exception e){
           e.printStackTrace();
       }
   }
}

六、自定义Realm(授权)

在这里插入图片描述
授权流程
在这里插入图片描述
在这里插入图片描述
我的测试类

public class TestCustomerMd5RealmAuthenicator {
    public static void main(String[] args) {
        //创建安全管理器
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //注入Realm
        CustomerMD5Realm realm = new CustomerMD5Realm();
        //设置realm使用hash凭证匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//使用md5加密
        hashedCredentialsMatcher.setHashIterations(1024);//hash散列次数
        realm.setCredentialsMatcher(hashedCredentialsMatcher);
        defaultSecurityManager.setRealm(realm);
        //将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();

        //认证
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoluo","123");
        try {
            subject.login(token);//用户认证
            System.out.println("认证状态:" + subject.isAuthenticated());//true
            System.out.println("登录成功");
        } catch (UnknownAccountException Un){
            Un.printStackTrace();
            System.out.println("认证失败:用户名错误!!");
        }catch (IncorrectCredentialsException In){
            In.printStackTrace();
            System.out.println("认证失败:密码错误!!");
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("==========");
        //认证的用户进行授权
        if(subject.isAuthenticated()){
            //1.基于单角色权限控制
            System.out.println(subject.hasRole("admin"));//true
            //2.基于多角色权限控制
            System.out.println(subject.hasAllRoles(Arrays.asList("admin", "users")));//true
            //3.是否具有其中一个角色
            boolean[] booleans=subject.hasRoles(Arrays.asList("admin", "users","super"));
            for(boolean aBoolean:booleans){
                System.out.println(aBoolean);//true//true//true
            }
            //4.基于权限字符串的访问控制, 资源标识符 : 操作:资源类型
            System.out.println("权限:"+subject.isPermitted("users:*:*"));//false
            System.out.println("权限:"+subject.isPermitted("users:*:01"));//true
            System.out.println("权限:"+subject.isPermitted("users:del:01"));//true

            //5. 分别具有哪些权限
            boolean[] permitted = subject.isPermitted("users:*:01", "order:*:01");
            for (boolean b:permitted
                 ) {
                System.out.println(b);//true  false
            }
            //6. 同时具有哪些权限
            boolean permittedAll = subject.isPermittedAll("users:*:01", "order:create:01");
            System.out.println(permittedAll);//true
        }
    }


}

我重写的授权方法(doGetAuthorizationInfo)

   @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        System.out.println("身份信息:"+primaryPrincipal);

        //根据身份信息 用户名 获取当前用户的角色信息
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("users");
        simpleAuthorizationInfo.addStringPermission("users:*:01");
        simpleAuthorizationInfo.addStringPermission("order:create");
        return simpleAuthorizationInfo;
    }

七、整合ssm+shiro框架

  1. 先整合ssm框架
    ssm整合博客

注:导入了 SLF4J就不需要导入log4j了

  1. 编写Shiroconfig类
@Configuration
@PropertySource("classpath:application.properties") 
@Import({ShiroBeanConfiguration.class,
       ShiroAnnotationProcessorConfiguration.class,
       ShiroWebConfiguration.class,
       ShiroWebFilterConfiguration.class,
       ShiroRequestMappingConfig.class})
public class ShiroConfig {

   @Bean
   public MyRealm realm(){
       return new MyRealm();//自定义的realm
   }

   @Bean
   public ShiroFilterChainDefinition shiroFilterChainDefinition() {
       DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
       chainDefinition.addPathDefinition("/view/login", "anon");  //anon是指未登录情况下  可以访问的页面
       chainDefinition.addPathDefinition("/user/login", "anon");
       chainDefinition.addPathDefinition("/**", "authc");
       return chainDefinition;
   }
}
  1. 创建application.properties类
application.properties

#设置登陆页面地址
shiro.loginUrl =
  1. 在web.xml 里面编写shiro过滤器
  <!--shiro过滤器-->
   <filter>
       <filter-name>shiroFilterFactoryBean</filter-name>
       <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
       <init-param>
           <param-name>targetFilterLifecycle</param-name>
           <param-value>true</param-value>
       </init-param>
   </filter>
   <filter-mapping>
       <filter-name>shiroFilterFactoryBean</filter-name>
       <url-pattern>/*</url-pattern>
   </filter-mapping>
  1. 我的shiroRelam
public class MyShrioRealm extends AuthorizingRealm {
 @Resource
   private TestService testService;

   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       //根据用户名查询角色
       //根据角色查询权限
       SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
       return simpleAuthenticationInfo;
   }

   //认证方法
   @Override
   protected SimpleAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       UsernamePasswordToken mytoken=(UsernamePasswordToken) authenticationToken;
       String username = mytoken.getUsername();
       Person name1 = testService.getName(username);
       if(name1==null){
           //用户名不存在
           throw new AccountException("用戶名不存在");
       }
       return new SimpleAuthenticationInfo(username,name1.getPassword(), getName());
   }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值