实现多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"/>

 

posted @ 2018-06-20 15:41  tuanz  阅读(1495)  评论(0编辑  收藏  举报