Learning -5- custom frame shiro Realm

1.  Custom Realm basis

  • step:
    • Create a class that inherits AuthorizingRealm-> AuthenticatingRealm-> CachingRealm-> Realm
    • Rewrite authorization method doGetAuthorizationInfo
    • Rewrite authentication method doGetAuthenticationInfo 
  • method:
    • When the user logs of calls doGetAuthenticationInfo
    • When checking the permissions will be called: doGetAuthorizationInfo
  • Object Description
    • UsernamePasswordToken: correspondence there is token shiro's Principal and Credential
      • UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
        
    • SimpleAuthorizationInfo: information on behalf of the user role permissions
    • SimpleAuthenticationInfo: on behalf of the user authentication information

2. Customize the realm of code:

package net.xdclass.xdclassshiro;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 自定义realm:继承AuthorizingRealm,重写抽象方法
 * / 
Public  class CustomRealm the extends AuthorizingRealm { 

    Private Final the Map <String, String> = userInfoMap new new the HashMap <> (); 
    { 
        userInfoMap.put ( " Jack " , " 123 " ); 
        userInfoMap.put ( " xdclass " , " 456 " ); 
    } 

    // role-> relationship permission simulation database role and authority of the 
    Private Final the Map <String, the Set <String >> permissonMap = new new HashMap <> ();
    {
        Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();
        set1.add("video:find");
        set1.add("video:buy");
        set2.add("video:add");
        set2.add("video:delete");
        permissonMap.put("jack", set1);
        permissonMap.put("xdclass", set2);
    }

    //user->relationship role simulation database roles and privileges of 
    private final Map<String, Set<String>> roleMap = new HashMap<>();
    {
        Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();
        set1.add("role1");
        set1.add("role2");
        set2.add("root");
        roleMap.put("jack", set1);
        roleMap.put("xdclass", set2);
    }


    /** 
     * This method is called when checking privileges, the principle is to package roles and permissions to SimpleAuthorizationInfo entity, shiro framework will help us to check permissions 
     * Final org.apache.shiro.realm.AuthorizingRealm # hasRole (org. apache.shiro.subject.PrincipalCollection, java.lang.String) 
     * method calls that return simpleAuthorizationInfo 
     * @param principalCollection 
     * @return simpleAuthorizationInfo 
     * / 
    @Override 
    protected AuthorizationInfo doGetAuthorizationInfo (principalCollection principalCollection) { 
        System. OUT .println ( " permission : doGetAuthorizationInfo " );
         // get the master account user name 
        String name = (String) principalCollection.getPrimaryPrincipal ();
        // Find by name authority, streamline operations (normal role is to find by name, by role query corresponding permissions) 
        the Set <String> = the Permissions getPermissonsByNameFromDB (name); 
        the Set <String> = the Roles getRolesByNameFromDB (name); 
        SimpleAuthorizationInfo simpleAuthorizationInfo = new new simpleAuthorizationInfo (); 
        simpleAuthorizationInfo.setRoles (Roles); simpleAuthorizationInfo.setStringPermissions (Permissions); 
        return simpleAuthorizationInfo; 
    } 

    Private the Set <String> getRolesByNameFromDB (String name) {
         return rolemap. GET (name); 
    } 

    Private the Set <String>getPermissonsByNameFromDB {(String name)
         return . permissonMap GET (name); 
    } 

    // when the user logs on will call the method 
    @Override
     protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken AuthenticationToken) throws AuthenticationException { 
        System. OUT .println ( " Certification: doGetAuthenticationInfo " );
         // obtain identity information from the token, token representing the user input information 
        String name = (String) authenticationToken.getPrincipal ();
         // the analog reading from the database password 
        String pwd = getPwdByUserNameFromDB (name);

        IF (StringUtils.isBlank (pwd)) { 
            // this judgment is needed to be added, the process returns null, that is, authentication is not passed! ! ! See source 
            return null; // match fails 
        } 
        / * useNmaePasswordToken in users of Principal and Credential 
        SimpleAuthorizationInfo behalf of the user role permissions information 
        SimpleAuthenticationInfo on behalf of the user authentication information * /
         // this.getName () is to obtain CachingRealm name 
       SimpleAuthenticationInfo = new new simpleAuthenticationInfo simpleAuthenticationInfo (name, pwd, this.getName ()); 
        return simpleAuthenticationInfo; 
    } 

    Private String getPwdByUserNameFromDB (String name) {
         return userInfoMap. GET (name); 
    } 
}

Test the code:

package net.xdclass.xdclassshiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Before;
import org.junit.Test;

/**
 * 自定义Realm操作
 */
public class QuicksStratTest5_4 {

    private CustomRealm customRealm = new CustomRealm();
    private DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
    @Before
    public void inint(){
        //构建环境
        defaultSecurityManager.setRealm(customRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
    }

    @Test
    public void testAuthentication() {
        //获取当前操作的主体
        Subject subject = SecurityUtils.getSubject();
        //模拟用户输入账号密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
        subject.login(usernamePasswordToken);
        System.out.println("认证 结果:" + subject.isAuthenticated());
        System.out.println("getPrincipal()=" + subject.getPrincipal());

        System.out.println("调用权限校验:subject.hasRole方法会调用自定义realm重写的doGetAuthorizationInfo方法");
        System.out.println("用户jack是否有root角色:" + subject.hasRole("root"));  //false
        // 权限校验
        subject.checkRole("role1");
        System.out.println("用户jack是否有role1角色:" + subject.hasRole("role1")); //true
        System.out.println("用户jack是否有video:find权限:" + subject.isPermitted("video:find")); //true
    }


}

上面代码中 ,subject.login方法很关键,是所有认证授权逻辑的入口,跟踪一下代码,可以发现subject.login方法实际调用过程如下:

总结一下,shiro认证的主要流程就是

        subject.login(usernamePasswordToken);
	DelegatingSubject->login()
	DefaultSecurityManager->login()
	AuthenticatingSecurityManager->authenticate()
	AbstractAuthenticator->authenticate()
	ModularRealmAuthenticator->doAuthenticate()
	ModularRealmAuthenticator->doSingleRealmAuthentication()
	AuthenticatingRealm->getAuthenticationInfo() 

需要注意的是:org.apache.shiro.authc.pam.ModularRealmAuthenticator#doAuthenticate 这个方法中,一般只配置一个realm,因此走的是doSingleRealmAuthentication 这个分支

 protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        this.assertRealmsConfigured();
        Collection<Realm> realms = this.getRealms();
        return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
    }

doSingleRealmAuthentication 分支源码如下:

protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
        if (!realm.supports(token)) {
            String msg = "Realm [" + realm + "] does not support authentication token [" + token + "].  Please ensure that the appropriate Realm implementation is " + "configured correctly or that the realm accepts AuthenticationTokens of this type.";
            throw new UnsupportedTokenException(msg);
        } else {
// 这里实际上调用的就是自定义realmz中重写了的getAuthenticationInfo方法,如果返回null,抛出UnknownAccountException,认证不通过 AuthenticationInfo info
= realm.getAuthenticationInfo(token); if (info == null) { String msg = "Realm [" + realm + "] was unable to find account data for the " + "submitted AuthenticationToken [" + token + "]."; throw new UnknownAccountException(msg); } else { return info; } } }

 在源码中,获取 AuthenticationInfo 认证信息,如果为空的话,抛出异常,这也是为什么自定义realm中 doGetAuthenticationInfo 方法中判断密码不正确时要返回null的原因;

doSingleRealmAuthentication 方法中的 AuthenticationInfo info = realm.getAuthenticationInfo(token) 调用了org.apache.shiro.realm.AuthenticatingRealm 类的getAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)方法,这个方法里面,调用了一行: info = this.doGetAuthenticationInfo(token),查找其实现类,就是我们自定义realm重写的的doGetAuthenticationInfo方法。

同理,shiro授权的主要流程如下:subject.checkRole方法是授权流程的入口

   subject.checkRole("admin")
	DelegatingSubject->checkRole()
	AuthorizingSecurityManager->checkRole()
	ModularRealmAuthorizer->checkRole()
	AuthorizingRealm->hasRole()
	AuthorizingRealm->doGetAuthorizationInfo()

 

 

Guess you like

Origin www.cnblogs.com/enjoyjava/p/12080135.html