多Realm验证策略

前言:多Realm验证,有时候会存在多Realm,不同的角色会有不同的验证逻辑,这个时候会需要多Realm。

首先这里编写两个Realm,并且返回name

Realm1:CustomerRealm

public class CustomerRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private UserService userService;

    @Override
    public String getName(){
        return "网页登录";
    }

    //授权

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

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();
        User user = null;
        user = userService.getUserByPrincipal(principal);
        if(null!=user){
//            return new SimpleAuthenticationInfo(principal,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());

            //这里可以直接存储为user
            return new SimpleAuthenticationInfo(user,user.getPassword(), new MySimpleByteSource(user.getSalt()),this.getName());
        }else{
            return null;
        }
    }
}

Realm2:Customer2Realm

public class Customer2Realm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private UserService userService;

    @Override
    public String getName(){
        return "app登录";
    }

    //授权

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

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principal = (String) authenticationToken.getPrincipal();
        User user = null;
        user = userService.getUserByPrincipal(principal);
        if(null!=user){
//            return new SimpleAuthenticationInfo(principal,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());

            //这里可以直接存储为user
            return new SimpleAuthenticationInfo(user,user.getPassword(), new MySimpleByteSource(user.getSalt()),this.getName());
        }else{
            return null;
        }
    }
}

多Realm分为两种场景:
一、多个Realm串联认证,只要一个Realm通过,就会通过验证。

public class shiroConfig {

    ... ...
    
    //创建shiro安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(CookieRememberMeManager rememberMeManager, DefaultWebSessionManager mySessionManager){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //配置rememberMe
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager);

        //配置session
        defaultWebSecurityManager.setSessionManager(mySessionManager);

        //如果有多个realm,如果没有配置Token和Authenticator,则两个realm穿行都验证,只要有一个认证成功,则通过
        ArrayList<Realm> realms = new ArrayList<>();
        realms.add(getCustomerRealm());
        realms.add(getCustomer2Realm());

        defaultWebSecurityManager.setRealms(realms);


        return defaultWebSecurityManager;
    }

	... ...

}

二、多个Realm分支认证
1.编写自定义Token继承UsernamePasswordToken,添加loginType属性

public class MyToken extends UsernamePasswordToken {
    private String loginType;
    public MyToken(String username,String password,String loginType){
        super(username, password);
        this.loginType = loginType;
    }

    public String getLoginType() {
        return loginType;
    }

    public void setLoginType(String loginType) {
        this.loginType = loginType;
    }
}

2.编写自定义认证器,继承ModularRealmAuthenticator,更改Realm策略

public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        this.assertRealmsConfigured();
        MyToken myToken = (MyToken) authenticationToken;
        String loginType = myToken.getLoginType();

        Collection<Realm> realms = this.getRealms();
        Collection<Realm> myRealms = this.getRealms();
        for(Realm realm:realms){
            if(realm.getName().startsWith(loginType)){
                myRealms.add(realm);
            }
        }
        //这里Realms为最终认证集合
        return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)myRealms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(myRealms, authenticationToken);
    }
}

3.shiroConfig

public class shiroConfig {

	... ...
   
    //创建shiro安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(CookieRememberMeManager rememberMeManager, DefaultWebSessionManager mySessionManager){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //配置rememberMe
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager);

        //配置session
        defaultWebSecurityManager.setSessionManager(mySessionManager);

        //如果多个Realm分支验证,则需要自定义认证器
        defaultWebSecurityManager.setAuthenticator(getMyModularRealmAuthenticator());

        ArrayList<Realm> realms = new ArrayList<>();
        realms.add(getCustomerRealm());
        realms.add(getCustomer2Realm());

        defaultWebSecurityManager.setRealms(realms);


        return defaultWebSecurityManager;
    }

   ... ...
   
}

4.注意提交认证时使用自定义Token

            MyToken token = new MyToken(user.getUsername(),user.getPassword(),"网页登录");
            subject.login(token);
上一篇:MySQL 8.0 字符串比较特殊案例小结


下一篇:Shiro 基础认证实现