• 实现多Realm时,可能会出现的问题


    问题背景 
    在实现多Realm时,扩展了ModularRealmAuthenticator 和 UsernamePasswordToken,于是在MyAuthenticationToken token = (MyAuthenticationToken) authenticationToken时出现了转型异常。

    扩展ModularRealmAuthenticator 的代码如下:

    public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
    
        @Override
        public AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
            MyAuthenticationToken token = (MyAuthenticationToken) authenticationToken;
            String loginType = token.getLoginType();
            Collection<Realm> realms = getRealms();
            Collection<Realm> authRealms = new ArrayList<>();
            for(Realm realm : realms){
                if(realm.getName().equals(loginType)){
                    authRealms.add(realm);
                }
            }
    
            if(authRealms.size() == 1){
                 return doSingleRealmAuthentication(authRealms.iterator().next(), token);
            } else {
                return doMultiRealmAuthentication(authRealms, token);
            }
        }
    
    }

    扩展UsernamePasswordToken的代码如下:

    public class MyAuthenticationToken extends UsernamePasswordToken {
    
        private String loginType;
    
        public MyAuthenticationToken(final String username, final String password, String loginType){
            super(username, password);
            this.loginType = loginType;
        }
    
        public String getLoginType() {
            return loginType;
        }
    
        public void setLoginType(String loginType) {
            this.loginType = loginType;
        }
    }

    从上面的扩展中我们看到,没有地方使用我们的自己扩展的MyAuthenticationToken类,只是转型而已,并没有去实例化它,这才是引起问题的根源,问题发现了要如何解决它呢?我们在配置的使用并并未制定表单过滤器,此时默认使用的是FormAuthenticationFilter,而Token默认使用的也是UsernamePasswordToken,由此看来,我们扩展的MyAuthenticationToken就成了摆设,此时就要想办法如何将我们的扩展引用到程序里去呢? 
    既然默认的是UsernamePasswordToken,那么是如何将UsernamePasswordToken注入的呢?我们进入默认的Filter(FormAuthenticationFilter)可以看到createToken,这个是创建Token的,那么似乎可以和我们的Token搭上边了,FormAuthenticationFilter中的createToken如下:

    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
            String username = this.getUsername(request);
            String password = this.getPassword(request);
            return this.createToken(username, password, request, response);
    }

    我们发现期间又调用了createToken,此createToken为父类的方法,我们可以看到FormAuthenticationFilter的声明为 public class FormAuthenticationFilter extends AuthenticatingFilter ,也即内部调用的token为AuthenticatingFilter的实现,继续看AuthenticatingFilter中的createToken实现,而createToken中又调用了自身createToken的重载,源码如下:

    protected AuthenticationToken createToken(String username, String password, ServletRequest request, ServletResponse response) {
            boolean rememberMe = this.isRememberMe(request);
            String host = this.getHost(request);
            return this.createToken(username, password, rememberMe, host);
        }
    
        protected AuthenticationToken createToken(String username, String password, boolean rememberMe, String host) {
            return new UsernamePasswordToken(username, password, rememberMe, host);
        }

    可以看到在重载的createToken中,UsernamePasswordToken终于现身了,那么此时,我们可以通过扩展FormAuthenticationFilter并重新createToken将我们扩展的Token引入即可,以下为扩展的FormAuthenticationFilter:

    public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    
        @Override
        protected MyAuthenticationToken createToken(ServletRequest request, ServletResponse response) {
            String username = getUsername(request);
            String password = getPassword(request);
            String loginType = request.getParameter("loginType");
            if("sys".equals(loginType)){
                return new MyAuthenticationToken(username, password, "sys");
            } else {
                return new MyAuthenticationToken(username, password, "wx");
            }
        }
    
    }

    扩展完成后,需要配置默认的过滤器为我们的扩展,shiro的配置如下:

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <property name="loginUrl" value="/login" />
            <property name="successUrl" value="/index"/>
            <property name="unauthorizedUrl" value="/403"/>
            <property name="filterChainDefinitions">
                <value>
                    /favicon.ico = anon
                    /logout = logout
                    /** = authc
                </value>
            </property>
            <property name="filters">
                <map>
                    <entry key="authc" value-ref="myFormAuthenticationFilter" />
                </map>
            </property>
        </bean>
    
        <bean id="myFormAuthenticationFilter" class="com.yuxiao.springboot.springbootmybatis.config.shiro.filter.MyFormAuthenticationFilter"/>
  • 相关阅读:
    Windows 认证小结
    Linux 提权学习小结
    ssrf与gopher与redis
    hacker101 CTF 学习记录(二)
    Hacker101 CTF 学习记录(一)
    libwebsockets支持外部eventloop变更
    ypipe, zmq的核心部件,并行读写的管道。
    std::regex与boost::regex的性能差5倍,有profile有真相。
    Spring整合WebSocket
    温故知新——Spring AOP(二)
  • 原文地址:https://www.cnblogs.com/tuanz/p/9204134.html
Copyright © 2020-2023  润新知