zoukankan      html  css  js  c++  java
  • Shiro Realm设计概念

    Realm

    shiro最干实事的,其行为有

    CachingRealm

    其行为主要是注入缓存管理器、控制缓存开关、提供关于缓存的公共行为,他不提供缓存具体的认证和授权信息,该部分由其子类具体缓存

    AuthenticatingRealm

    具备缓存从数据库查出的用户信息(Cache<Object, AuthenticationInfo>),其行为主要是执行认证的具备行为,其具备CredentialsMatcher凭证匹配器,主要用于匹配用户输入的Token和数据库查出的Info是否匹配。该部分的用户信息还会注入到Subject中,为校验用户权限使用,但是就有了一个问题,用户的权限更新后怎么办,Shiro使用了runAs方式。 

    用户的权限信息更新后需要更新Subject中获取PrincipalCollection的方式,即runAs()方式,还需更新认证、授权缓存信息

    package com.wjz.demo;
    
    import org.apache.shiro.SecurityUtils;
    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.cache.Cache;
    import org.apache.shiro.cache.CacheManager;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.SimplePrincipalCollection;
    import org.apache.shiro.subject.Subject;
    
    public class CustomAuthorizingRealm extends AuthorizingRealm {
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            return new SimpleAuthenticationInfo("wjz", "123", getName());
        }
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            authorizationInfo.addRole("buyGoods");
            return authorizationInfo;
        }
    
        /**
         * 用户的权限信息被更新后须执行该方法
         * 
         * @param latestPrincipal
         *            最新的用户权限信息
         */
        public void reloadAuthorizing(Object latestPrincipal) {
            Subject subject = SecurityUtils.getSubject();
            PrincipalCollection expiredPrincipalCollection = subject.getPrincipals();
            String realmName = getName();
            final SimplePrincipalCollection latestPrincipalCollection = new SimplePrincipalCollection(latestPrincipal,
                    realmName);
            subject.releaseRunAs();
            subject.runAs(latestPrincipalCollection);
    
            // 如果认证、授权还有缓存功能的话执行以下内容
            if (isCachingEnabled()) {
                clearCache(expiredPrincipalCollection);
    
                CacheManager cacheManager = getCacheManager();
                if (isAuthenticationCachingEnabled()) {
                    Cache<Object, AuthenticationInfo> authenticationCache = cacheManager
                            .getCache(getAuthenticationCacheName());
                    setAuthenticationCache(authenticationCache);
                }
                if (isAuthorizationCachingEnabled()) {
                    Cache<Object, AuthorizationInfo> authorizationCache = cacheManager
                            .getCache(getAuthorizationCacheName());
                    setAuthorizationCache(authorizationCache);
                }
            }
        }
    }

    核心逻辑方法

    public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
        // 试图从缓存中获得,没有缓存时使用CacheManager创建
        AuthenticationInfo info = getCachedAuthenticationInfo(token);
        if (info == null) {
            // 子类具体实现返回具有从数据库查出的用户信息的AuthenticationInfo
            info = doGetAuthenticationInfo(token);
            log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
            if (token != null && info != null) {
                // 开启了缓存的话将AuthenticationInfo放到缓存中,Token的principal为key(UsernamePasswordToken的principal即username)
                cacheAuthenticationInfoIfPossible(token, info);
            }
        } else {
            log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
        }
    
        if (info != null) {
            // Token和Info进行匹配
            assertCredentialsMatch(token, info);
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }
    
        return info;
    }

    AuthorizingRealm

    具备了权限解析器(PermissionResolver)和从数据库查出的用户权限缓存(Cache<Object, AuthorizationInfo>),其行为主要是校验用户的权限

    核心逻辑方法根据Subject中的PrincipalCollection获得会员的权限信息

    protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
    
        if (principals == null) {
            return null;
        }
    
        AuthorizationInfo info = null;
    
        if (log.isTraceEnabled()) {
            log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
        }
    
        Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
        if (cache != null) {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to retrieve the AuthorizationInfo from cache.");
            }
            Object key = getAuthorizationCacheKey(principals);
            info = cache.get(key);
            if (log.isTraceEnabled()) {
                if (info == null) {
                    log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
                } else {
                    log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");
                }
            }
        }
    
    
        if (info == null) {
            // 子类具体实现返回具有从数据库查出的用户权限信息的AuthorizationInfo
            info = doGetAuthorizationInfo(principals);
            // If the info is not null and the cache has been created, then cache the authorization info.
            if (info != null && cache != null) {
                if (log.isTraceEnabled()) {
                    log.trace("Caching authorization info for principals: [" + principals + "].");
                }
                // 开启了缓存的话将AuthorizationInfo放到缓存中,PrincipalCollection为key
                Object key = getAuthorizationCacheKey(principals);
                cache.put(key, info);
            }
        }
    
        return info;
    }

    校验前期准备

    public boolean isPermitted(PrincipalCollection principals, String permission) {
        // 使用权限解析器解析字符串获得用户的权限信息,实例化 WildcardPermission 并注入权限字符串
        Permission p = getPermissionResolver().resolvePermission(permission);
        return isPermitted(principals, p);
    }
    
    public boolean isPermitted(PrincipalCollection principals, Permission permission) {
        // 调用核心逻辑方法获得用户的权限信息
        AuthorizationInfo info = getAuthorizationInfo(principals);
        return isPermitted(permission, info);
    }

    具体的校验

    protected Collection<Permission> getPermissions(AuthorizationInfo info) {
        Set<Permission> permissions = new HashSet<Permission>();
    
        // 当子类查询数据库查出用户权限信息后拼装AuthorizationInfo时可以注入字符串权限
        // 也可以注入对象权限即 WildcardPermission 
        if (info != null) {
            Collection<Permission> perms = info.getObjectPermissions();
            if (!CollectionUtils.isEmpty(perms)) {
                permissions.addAll(perms);
            }
            // 是字符串权限的话还得解析为对象权限 WildcardPermission
            perms = resolvePermissions(info.getStringPermissions());
            if (!CollectionUtils.isEmpty(perms)) {
                permissions.addAll(perms);
            }
    
            perms = resolveRolePermissions(info.getRoles());
            if (!CollectionUtils.isEmpty(perms)) {
                permissions.addAll(perms);
            }
        }
    
        if (permissions.isEmpty()) {
            return Collections.emptySet();
        } else {
            return Collections.unmodifiableSet(permissions);
        }
    }
    
    //visibility changed from private to protected per SHIRO-332
    protected boolean isPermitted(Permission permission, AuthorizationInfo info) {
        Collection<Permission> perms = getPermissions(info);
        if (perms != null && !perms.isEmpty()) {
            for (Permission perm : perms) {
                // 权限匹配
                if (perm.implies(permission)) {
                    return true;
                }
            }
        }
        return false;
    }

     

  • 相关阅读:
    对我影响最大的老师
    介绍自己
    JavaScript 时间特效 显示当前时间
    js 获取函数的所有参数名
    node.js 在函数内获取当前函数
    js 实现二叉排序树
    命令行下mysql的部分操作
    浅析js的函数的按值传递参数
    返回上一页时,保存恢复浏览记录(模拟返回不刷新)
    让mongodb执行js文件
  • 原文地址:https://www.cnblogs.com/BINGJJFLY/p/9525546.html
Copyright © 2011-2022 走看看