shiro入门

shiro

什么是shiro

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

shiro的功能

三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
  Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
  SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
  Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
  从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
  Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

入门小案例

  • 引入shiro相关依赖
 <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.5.3</version>
 </dependency>
  • 创建一个shiro.ini的配置文件,用来学习shiro书写权限相关的数据。
[users]
szl=123
lh=456
cs=789

随意设置几组用户信息,以键值对的方式设置。

  • 新建一个TestAuthenticator类
/**
 * @ClassName TestAuthenticator
 * @Description TODO
 * @Author szl
 * @Date: Created in 9:33 2020/6/25
 * @Version 1.0
 **/
public class TestAuthenticator {
    public static void main(String[] args) {
        //创建安全管理对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //给安全管理器设置realm
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
        //给全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //获取关键对象subject主体
        Subject subject = SecurityUtils.getSubject();
        //创建令牌token
        UsernamePasswordToken token = new UsernamePasswordToken("szl","123");
        try {
            System.out.println("认证状态:"+subject.isAuthenticated());
            subject.login(token);
            System.out.println("认证状态:"+subject.isAuthenticated());
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("登陆失败");
        }

    }
}

自定义realm的实现,将认证的数据来源转为数据库

  • 先创建一个realm类CustomerRealm
public class CustomerRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
}
  • 创建一个测试类TestCustomerRealmAuthenticator
public class TestCustomerRealmAuthenticator {
    public static void main(String[] args) {
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(new CustomerRealm());
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("szl", "123");
        try{
            subject.login(token);
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("找不到该用户");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
    }
}
  • 创建的realm中返回为null,所以测试类中报错为UnknownAccountException
  • 在重写的方法doGetAuthenticationInfo中添加返回对象如下:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        System.out.println(principal);
        if ("szl".equals(principal)) {
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,"123",this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }

MD5加密和salt

  • 使用MD5加密后的数值与加了salt以后已经使用hash多次散列后的完全不同。
public class TestShiroMd5 {
    public static void main(String[] args) {
        //使用MD5
        Md5Hash md5Hash = new Md5Hash("123");
        System.out.println(md5Hash.toHex());
        //使用MD5+salt
        Md5Hash md5hash1 = new Md5Hash("123", "qwe");
        System.out.println(md5hash1.toHex());
        //使用MD5+salt+hash
        Md5Hash md5Hash2 = new Md5Hash("123", "qwe", 1024);
        System.out.println(md5Hash2.toHex());
    }
}
  • 要实现MD5在shiro中的使用,则需要设置算法已经散列次数
public class TestCustomerMd5RealmAuthenticator {
    public static void main(String[] args) {
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        CustomerMd5Realm realm = new CustomerMd5Realm();
        //设置realm使用hash凭证匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //使用算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //使用散列
        hashedCredentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(hashedCredentialsMatcher);
        defaultSecurityManager.setRealm(realm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("szl", "123");
        try {
            subject.login(token);
            System.out.println("登录成功");
        }catch(UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名不存在");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
    }
}
  • realm类中,同时也要有相关的配置, ByteSource.Util.bytes("qwe")用来设置salt的值.
public class CustomerMd5Realm extends AuthorizingRealm {

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();
        if("szl".equals(principal)){
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,
                  "514f70e88fd768b45c04f1c51871b784",
                  //  "123",
                    ByteSource.Util.bytes("qwe"),
                    this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}
posted @ 2020-06-26 10:34  promise911  阅读(195)  评论(0编辑  收藏  举报