• shiro笔记(二)


    使用shiro进行认证通常不会将用户信息直接写在ini文件中,目前假设从某数据源中获取用户信息,密码暂不加密一切从简。获取数据的这一步操作就要交给realm(域)来进行。

    而认证是由securityManager指派认证器来完成,所以需要将自定义的realm交给securityManager。

    首先,实现一个自定义的realm,没有继承AuthorizingRealm,而是直接实现realm接口(因为教程上是这么做的,这个应该是按照需求而决定)。

    public class SelfRealm implements Realm {
        @Override
        public String getName() {
            return "SelfRealm"; //realm的名字
        }
    
        @Override
        public boolean supports(AuthenticationToken authenticationToken) {
            return authenticationToken instanceof UsernamePasswordToken; //支持的token类型
        }
    
        @Override
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            String username = (String) authenticationToken.getPrincipal();
            String password = new String((char[])authenticationToken.getCredentials());
            if(!"joker".equals(username)) { //模拟从数据源获取用户名
                throw new UnknownAccountException();
            }
            if(!"shiro".equals(password)) { //模拟从数据源获取密码
                throw new IncorrectCredentialsException();
            }
            return new SimpleAuthenticationInfo(username, password, getName());
        }
    }

    测试类

    public class Test {
    
        @org.junit.Test
        public void test() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //创建核心管理器
            securityManager.setRealm(new SelfRealm()); //将自定义的realm交给核心管理器
            SecurityUtils.setSecurityManager(securityManager);
            Subject subject = SecurityUtils.getSubject(); //获取主体
            UsernamePasswordToken token = new UsernamePasswordToken("joker", "shiro"); //创建token
            subject.login(token); //登录
        }
    }

    进行认证时会调用getAuthenticationInfo方法,UsernamePasswordToken是AuthenticationToken的实现类,subject.isAuthenticated()可以获取认证的状态,true为成功,false为失败。

    以上为单realm配置,在shiro还支持多realm配置,可以配置在ini文件中。

    #声明realm  
    FirstRealm=全类名
    SecondRealm=全类名 
    #配置securityManager的realms 
    securityManager.realms=$FirstRealm,$SecondRealm

    会按照realm的配置顺序进行认证,如果没有再ini文件中配置,则会按照声明顺序进行认证,当在ini文件中配置了realm时,没有写入配置的realm会被忽略。

    那是否可以不通过配置文件来设置realm呢?

    接下来我自己动手实践了一下,首先对自定义realm进行改造。

    public class SelfRealm implements Realm {
    
        Integer id;
    
        public SelfRealm(Integer id) { //创建实例对象时,为对象设置一个id
            this.id = id;
        }
    
        @Override
        public String getName() {
            return "SelfRealm";
        }
    
        @Override
        public boolean supports(AuthenticationToken authenticationToken) {
            return authenticationToken instanceof UsernamePasswordToken;
        }
    
        @Override
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println(id); //在执行认证操作时,将id打印到控制台
            String username = (String) authenticationToken.getPrincipal();
            String password = new String((char[])authenticationToken.getCredentials());
            if(!"joker".equals(username)) {
                throw new UnknownAccountException(); 
            }
            if(!"shiro".equals(password)) {
                throw new IncorrectCredentialsException(); 
            }
            return new SimpleAuthenticationInfo(username, password, getName());
        }
    }

    然后将两个仅仅是id不同的realm交给securityManager,观察是否会按照设置的先后顺序进行执行?是否两个realm都会被执行?

    测试方法部分改造如下:

    securityManager.setRealm(new SelfRealm(0));
    securityManager.setRealm(new SelfRealm(2));

    但是结果是id为2的realm被执行,而id为0的realm对象没有被执行,看来应该是被id为2的覆盖掉了。

    接下来我进入了源码看了一下,发现了setRealms方法,setRealms(Collection<Realm> realms),可以传入集合参数,这波应该是稳了。

    public class Test {
    
        @org.junit.Test
        public void test() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            List<Realm> selfRealmList = new ArrayList<>();
            selfRealmList.add(new SelfRealm(0));
            selfRealmList.add(new SelfRealm(2));
            securityManager.setRealms(selfRealmList);
            SecurityUtils.setSecurityManager(securityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("joker", "shiro");
            try {
                subject.login(token);
            } catch (Exception e) {}
            System.out.println(subject.isAuthenticated());
        }
    }

    果然这次两个realm都被执行,并且是按照添加进集合的顺序执行的。

    接下来教程中提到了一些关于自定义realm的常用做法和shiro提供的默认realm:

    一般继承AuthorizingRealm,它继承了AuthenticatingRealm(身份验证),而且也间接继承了CachingRealm(带有缓存实现)。

    主要默认实现有:IniRealm、PropertiesRealm、JdbcRealm。

    接下在教程中介绍了一下JdbcRealm的使用,以及三种认证策略,没有找到用代码设置认证策略的方式,所以此处暂不记录。

  • 相关阅读:
    (转载)Android多渠道打包飞一般的感觉
    (转载)【笨木头Lua专栏】基础补充22:弱引用table
    (转载)【笨木头Lua专栏】基础补充21:面向对象——多重继承、私密性
    (转载)【笨木头Lua专栏】基础补充20:面向对象——类和继承
    (转载)【笨木头Lua专栏】基础补充19:调用函数时用点号还是用冒号
    (转载)【笨木头Lua专栏】基础补充18:Lua的模块编写与module函数
    (转载)【笨木头Lua专栏】基础补充16:__index和__newindex的沉默与合作
    (转载)【笨木头Lua专栏】基础补充17:全局变量与非全局环境
    自定义web浏览器(五)
    第九课时之错误和异常
  • 原文地址:https://www.cnblogs.com/wxdmw/p/13896499.html
Copyright © 2020-2023  润新知