shiro中自定义的realm交给spring管理,是单例好呢还是多例好

最近使用shiro做权限管理,想问下shiro中自定义的realm托管给spring,是单例好呢还是多例好?希望有大牛可以分享一下,如果能给出相关的文档,那就更感谢了。本菜更偏向使用单例,但是项目中配置的是多例,因此有这个疑惑,谢谢大家了

补充代码:

public class ShiroDbRealmService extends AuthorizingRealm {

    /**
     * 用户service接口
     */
    private IUserService userService;

    /**
     * 日志打印
     */
    private static Logger logger = LoggerFactory.getLogger(ShiroDbRealmService.class);

    /**
     * 支持什么类型的token
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        // TODO Auto-generated method stub
        return super.supports(token);
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("principals不能为空");
        }
        //多例的情况下,不同实例的getName()返回的值是不一样的
        User user = (User) principals.fromRealm(getName()).iterator().next();
        if (user == null) {
            throw new UnknownAccountException("用户不存在");
        }
        SimpleAuthorizationInfo authorizationInfo = getAuthorizationInfoFromMem(user);
        return authorizationInfo;

    }

    /**
     * 从缓存中获取授权信息
     * 
     * @return
     */
    private SimpleAuthorizationInfo getAuthorizationInfoFromMem(User user) {
        System.out.println("get author info...");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 从缓存中获取相应的信息
        UserResource userResource = (UserResource) ShiroSession.getSessionInstance()
                .getAttribute(LoginEnum.USER_AUTHOR_INFO.getKey());
        // 如果缓存中没有,再次调用
        if (userResource != null) {
            // 转化
            Map<String, Station> stationMap = userResource.getStationMap();
            if (!stationMap.isEmpty()) {
                Station station = stationMap
                        .get(ShiroSession.getSessionInstance().getAttribute(LoginEnum.USER_STATION_INFO.getKey()));
                // TODO 解析岗位信息,角色,权限
                List<Role> roleList = station.getRoleList();
                for (Role role : roleList) {
                    info.addRole(role.getName());
                    List<Resource> resList = role.getResList();
                    for (Resource resource : resList) {
                        info.addStringPermission(resource.getPremsCode());
                    }
                }
            }
        }
        return info;
    }

    /**
     * 登录信息和用户验证信息验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
            throws AuthenticationException {
        /* Subject subject = ShiroSession.getSubjectInstance(); */
        UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken) authcToken;
        // 校验验证码
        if (doCaptchaValidate(token)) {
            // 通过登录名去查询
            User user = userService.selectUserByLoginName(token.getUsername());
            if (user != null) {
                return new SimpleAuthenticationInfo(user, (user.getPassword()).toLowerCase(), this.getName());
            }
            else {
                throw new UnknownAccountException("用户不存在");
            }
        }
        else {
            throw new CaptchaException("验证码异常");
        }
    }

    /**
     * 验证码校验
     * 
     * @param token
     * @return boolean
     */
    protected boolean doCaptchaValidate(UsernamePasswordCaptchaToken token) {
        String captcha =
                (String) SecurityUtils.getSubject().getSession().getAttribute(LoginEnum.LOGIN_CAPTCHA.getKey());
        logger.info(captcha);
        if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptchaCode())) {
            throw new CaptchaException("验证码错误!");
        }
        return true;
    }

    @Autowired
    public void setUserService(IUserService userService) {
        this.userService = userService;
    }

    /**
     * 用户切换岗位时清除缓存的信息
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }
    
    @Override
    public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
        return super.getAuthorizationInfo(principals);
    }
}

因为我要在controller注入realm对象(因为切换岗位时要手动设置shiro缓存的权限信息),如果是spring 多例管理的话,在调用时,每个realm的getName()是不一样的,执行getAuthorizationInfo()方法会出现问题;所以请教把当前realm配置成为单例,getName()是一样的,就可以使用controller中配置的realm调用getAuthorizationInfo()方法,手动的处理shiro的权限管理

阅读 6.7k
1 个回答

没有代码很难猜到为什么要使用多例。
一个Realm通常作为一个公用服务,每一次调用都应该是相同的实例。
如果不是singleton,也就是说这个Realm是有状态的,题主看一下,您的Realm是不是根据不同的状态提供不同的认证服务?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题