(四)自定义多个Realm以及Authenticator与AuthenticationStrategy

  • Realm配置

    #声明一个realm  
    myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1  
    myRealm2=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm2  
    #指定securityManager的realms实现  
    securityManager.realms=$myRealm1,$myRealm2   
  1. securityManager会按照realms指定的顺序进行身份认证。此处我们使用显示指定顺序的方式指定了Realm的顺序,如果删除“securityManager.realms=$myRealm1,$myRealm2”,那么securityManager会按照realm声明的顺序进行使用(即无需设置realms属性,其会自动发现),当我们显示指定realm后,其他没有指定realm将被忽略,如“securityManager.realms=$myRealm1”,那么myRealm2不会被自动设置进去
  2. 1、变量名=全限定类名会自动创建一个类实例

    2、变量名.属性=值 自动调用相应的setter方法进行赋值

    3、$变量名 引用之前的一个对象实例

  •   AuthenticatorAuthenticationStrategy

  1. Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:
    public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)  
                throws AuthenticationException;   
  • SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现(ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。),其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:
  • FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
  • AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
  • AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。

一、案例

  • 需求:

    假设我们有三个realm:

    myRealm1: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang/123;

    myRealm2: 用户名/密码为wang/123时成功,且返回身份/凭据为wang/123;

    myRealm3: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang@163.com/123,和myRealm1不同的是返回时的身份变了;

  • pom.xml依赖省略,可查看前几章
  • 配置shiro.ini文件
[main]
#指定securityManager的authenticator实现  authenticator
=org.apache.shiro.authc.pam.ModularRealmAuthenticator securityManager.authenticator=$authenticator

#指定securityManager.authenticator的authenticationStrategy allSuccessfulStrategy
=org.apache.shiro.authc.pam.FirstSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
myRealm1
=realms.MyRealm1 myRealm2=realms.MyRealm2 myRealm3=realms.MyRealm3 securityManager.realms=$myRealm1,$myRealm2,$myRealm3 [users] zhang=123 wang=123
    •   认证策略为FirstSuccessfulStrategy ,只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略
  • MyRealm1.java
package realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class MyRealm1 extends AuthorizingRealm{

    /**
     * 判断授权的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 判断认证的
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName=token.getPrincipal().toString();
        String passWord=new String((char[])token.getCredentials());
        
        if(!userName.equals("zhang")) throw new UnknownAccountException("Realm1 用户名错误");
        if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm1 密码错误");
        
        return new SimpleAccount(userName, passWord, getName());
    }

}
  • MyRealm2.java
package realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class MyRealm2 extends AuthorizingRealm{
    /**
     * 判断授权的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 判断认证的
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName=token.getPrincipal().toString();
        String passWord=new String((char[])token.getCredentials());
        
        if(!userName.equals("wang")) throw new UnknownAccountException("Realm2 用户名错误");
        if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm2 密码错误");
        
        return new SimpleAccount(userName, passWord, getName());
    }

}
  • MyRealm3.java
package realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class MyRealm3 extends AuthorizingRealm{
    /**
     * 判断授权的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 判断认证的
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName=token.getPrincipal().toString();
        String passWord=new String((char[])token.getCredentials());
        
        if(!userName.equals("zhang")) throw new UnknownAccountException("Realm3 用户名错误");
        if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm4 密码错误");
        
        return new SimpleAccount("zhang@163.com", passWord, getName());
    }

}
  • 测试
package test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

public class TestMain {
    public static void main(String[] args) {
        SecurityManager securityManager=new IniSecurityManagerFactory("classpath:shiro.ini").getInstance(); 
        SecurityUtils.setSecurityManager(securityManager);
        
        Subject subject=SecurityUtils.getSubject();
    
        AuthenticationToken token=new UsernamePasswordToken("zhang","123");
        try {
            subject.login(token);
            PrincipalCollection ps=subject.getPrincipals();
            System.out.println(ps.asList());
            
            System.out.println(ps.getRealmNames());
            System.out.println(subject.getPrincipal().toString());
            
        } catch (UnknownAccountException e) {
            System.out.println(e.getMessage());
        }catch(IncorrectCredentialsException e){
            System.out.println(e.getMessage());
        }
        
    }
}
  • 结果:

因为是FirstSuccessfulStrategy策略,myRealm1认证成功,所以只返回这个Realm的认证信息,其他的省略。

  • 修改shiro.ini,认证策略修改为AtLeastOneSuccessfulStrategy ,其他文件均不变
[main]
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator  
securityManager.authenticator=$authenticator  
atLeastOneSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy  
securityManager.authenticator.authenticationStrategy=$atLeastOneSuccessfulStrategy  
myRealm1=realms.MyRealm1  
myRealm2=realms.MyRealm2  
myRealm3=realms.MyRealm3  
securityManager.realms=$myRealm1,$myRealm2,$myRealm3  

[users]
zhang=123
wang=123

  •  修改shiro.ini,认证策略修改为AllSuccessfulStrategy,其他文件均不变
[main]
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator  
securityManager.authenticator=$authenticator  
atLeastOneSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy  
securityManager.authenticator.authenticationStrategy=$atLeastOneSuccessfulStrategy  
myRealm1=realms.MyRealm1  
myRealm2=realms.MyRealm2  
myRealm3=realms.MyRealm3  
securityManager.realms=$myRealm1,$myRealm2,$myRealm3  

[users]
zhang=123
wang=123

原文地址:https://www.cnblogs.com/shyroke/p/7808812.html