RBAC权限与shiro中登录与session的思考

RBAC权限与shiro中登录与session的思考

1. 用户登录状态的思考

1.1 Session

参考

多态电脑登录同一个用户/一台电脑登录多个用户

服务端如何识别并处理?

cookie/session 来保存交互记录从而实现更多功能

Session 提供了一种用户跨多个页面请求/访问某个web 服务器的用户信息跟踪、识别机制。

Session在网络协议中表示面向连接、保持状态的含义

session的实现也许借助cookie在客户端保存标识以便用户身份认证

1.2 cookie

由浏览器存储的源自于web服务器的少量信息交互机制,常用于session管理

用于记录用户信息形成特定访问状态

  1. 名称 key
  2. 值 value
  3. 路径 域+路径取顶作用范围
  4. 过期时间

用于记录session的cookie 例如 jsessionid

浏览器关闭不会让cookie失效,因此服务器自己必须设置失效时间,也可在登出时手动情况登录状态

Weblogic Server对于HttpSession的默认实现是存在内存中,服务器一旦重启就丢失这些登录信息的session信息,因此shiro交给redis管理后即使重启依旧可以重复获取从而在一定程度上保证登录可靠

1.3 shiro中的session

通过配置DefaultWebSessionManager来控制session的执行规则

DefaultWebSessionManager$storeSessionId方法中可看到默认的session设置是通过cookie

自定义cookie / 请求头

shiro会寻找session id,源码中默认使用JSESSIONID 作为shiro的默认sessionId

可通过重写DefaultWebSessionManager#getSessionId方法来自定义session ID

/**
 * 自定义session管理
 */
@Configuration
@Slf4j
public class MySessionManager extends DefaultWebSessionManager {
    @Resource
    LoginUtil loginUtil;

    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";

    public MySessionManager() {
        super();
    }

    /**
     * api接口使用公共token替代登录session,作为登录标识
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader("cSession");
        //如果请求头中有 token 则其值为sessionId
        if (!CommonUtil.isNullOrEmpty(id)) {
            try {
                id = loginUtil.decryptText(id);
            } catch (NoAuthException e) {
                id = "";
            }
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        }
        //否则按默认规则从cookie取sessionId
        return super.getSessionId(request, response);
    }
}

2.数据库设计

字典表设计属于EAV模型

使用key+value+valuetype表示可扩展的行,无法保证数据一致性,数据膨胀、笨重

解决方案

  1. 单表集成所有属性(由于属性扩展无法达成) type区分
  2. 多表扩展,元数据膨胀
  3. 类表集成,外键指向共同属性表的某个字段

下面介绍设计中改动较大的部分

2.1 sys_permission

通过operator_visibility(操作员是否可见)、permission_system_visibility(权限系统是否可见)两个字段定义菜单可见性,解决两个问题

  1. 识别权限管理系统自身菜单在各个系统空间的可见性

    permission_system_visibility1permission_system_visibility-1
    operator_visibility1权限系统/其他系统空间均可见 例如角色管理权限系统不可见,其他系统可见 例如操作员管理
    operator_visibility-1权限系统可见,其他系统不可见 例如系统管理权限系统,其他系统在权限管理系统内都不可见 例如其他系统自身的权限
  2. 区分权限系统的菜单/其他系统自身配置的菜单

    其他系统自身配置的菜单对权限系统/操作员 均不可见

2.2 sys_role

同样通过两个字段区分普通角色/操作员角色/其他系统普通角色

  1. app_id

    所属系统

  2. use_role_app_id

    使用该角色的系统(主要用于区分普通角色/操作员角色 操作员角色的使用角色的系统默认为1 (权限管理系统) 普通角色则系统默认与所属系统一致

同样分为四种情况(假定权限管理系统的系统代码为1,其他系统为-1)

  • app_id = 1 | use_role_app_id = 1

    所属系统为权限管理系统,使用该角色的系统也是权限管理系统,那么这个角色就是为权限管理系统自身配置的角色,可登录权限管理系统在权限管理系统空间内操作

  • app_id = 1 | use_role_app_id = -1

    所属系统为权限管理系统,使用该角色的系统非权限管理系统(这种情况暂时未遇到)

  • app_id = -1 | use_role_app_id = 1

    例如操作员角色,所属系统非权限管理,但需要到权限管理系统来做操作配置

  • app_id = -1 | use_role_app_id = -1

    例如非权限管理系统空间内配置的普通角色,服务于其他系统

3. shiro用户登录信息变更

  1. 从缓存获取当前用户登录信息变更后假设以另一个身份登录(切换了系统空间)

            // 更新用户信息
            StaffLoginVo validStaffInfo = loginCacheUtil.getValidStaffInfo();
            // log 添加关键字,手机号去除,占位符拼接
            log.info("模块:用户系统空间切换 操作参数:{},切换前用户信息{}",appId,validStaffInfo);
            validStaffInfo.setAppId(appId);
            Subject subject = SecurityUtils.getSubject();
            String newLoginInfo = JSON.toJSONString(validStaffInfo);
    
            PrincipalCollection principals = subject.getPrincipals();
            String realmName = principals.getRealmNames().iterator().next();
    
            // 生成新的principal
            PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(newLoginInfo, realmName);
            // 用户身份切换
            subject.runAs(newPrincipalCollection);
    
            log.info("模块:用户系统空间切换 操作参数:{},切换后用户信息{}",appId,validStaffInfo);
    
  2. 删除旧的授权信息,在访问shiro权限校验注解标注的controller方法时重新获取用户权限

        /**
         * 根据principalCollection删除授权缓存
         * @param attribute
         */
        public void deleteCacheBySimplePrincipalCollection(SimplePrincipalCollection attribute) {
            //删除Cache,再访问受限接口时会重新授权
            DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
            Authenticator authc = securityManager.getAuthenticator();
            ((LogoutAware) authc).onLogout(attribute);
        }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值