前言
什么是jasbin?
概述
Casbin是一个弱小的、高效的开源访问控制框架,其权限管理机制反对多种访问控制模型
Casbin反对以下编程语言:
Casbin 能够:
反对自定义申请的格局,默认的申请格局为{subject, object, action}。
具备访问控制模型model和策略policy两个外围概念。
反对RBAC中的多层角色继承,不止主体能够有角色,资源也能够具备角色。
反对内置的超级用户 例如:root或administrator。超级用户能够执行任何操作而无需显式的权限申明。
反对多种内置的操作符,如 keyMatch,不便对门路式的资源进行治理,如 /foo/bar 能够映射到 /foo*
Casbin 不能:
身份认证 authentication(即验证用户的用户名、明码),casbin只负责访问控制。应该有其余专门的组件负责身份认证,而后由casbin进行访问控制,二者是相互配合的关系。
治理用户列表或角色列表。 Casbin 认为由我的项目本身来治理用户、角色列表更为适合, 用户通常有他们的明码,然而 Casbin 的设计思维并不是把它作为一个存储明码的容器。 而是存储RBAC计划中用户和角色之间的映射关系。
什么是RBAC?
基于角色的访问控制(RBAC)是施行面向企业安全策略的一种无效的访问控制形式。
其根本思维是,对系统操作的各种权限不是间接授予具体的用户,而是在用户汇合与权限汇合之间建设一个角色汇合。每一种角色对应一组相应的权限。一旦用户被调配了适当的角色后,该用户就领有此角色的所有操作权限。这样做的益处是,不用在每次创立用户时都进行调配权限的操作,只有调配用户相应的角色即可,而且角色的权限变更比用户的权限变更要少得多,这样将简化用户的权限治理,缩小零碎的开销。
如何应用Casbin?
想要明确如何应用casbin,必须要分明model和policy两个概念,即模型和资源,能够参考官网文档
https://casbin.org/zh-CN/ 学习。
springboot集成casbin
1.pom.xml文件增加依赖
<!--jcasbin--> <dependency> <groupId>org.casbin</groupId> <artifactId>jcasbin</artifactId> <version>1.4.0</version> </dependency> <!--casbin适配器(上面会概述)--> <dependency> <groupId>org.casbin</groupId> <artifactId>jdbc-adapter</artifactId> <version>2.0.0</version> </dependency>
2.定义model模型,这里是应用RBAC+RESTFUL进行模型的定义。
[request_definition]r = sub, obj, act[policy_definition]p = sub, obj, act[role_definition]g = _, _[policy_effect]e = some(where (p.eft == allow))[matchers]m = g(r.sub,p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)
3.创立casbin适配器类,将datasource数据源写入casbin的适配器
@Slf4j@Configurationpublic class CasbinAdapterConfig { private final DataSource dataSource; @Autowired public CasbinAdapterConfig(DataSource dataSource) { this.dataSource = dataSource; } @Bean public JDBCAdapter adapterConfig() throws Exception { return new JDBCAdapter(dataSource); }}
4#.创立一个初始化的配置类,并且继承InitializingBean接口
InitializingBean接口为bean提供了初始化办法的形式,它只包含afterPropertiesSet办法,但凡继承该接口的类,在初始化bean的时候都会执行该办法。
@Componentpublic class EnforcerFactory implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { } }
5.EnforcerFactory配置类中加载模型和适配器
@Componentpublic class EnforcerFactory implements InitializingBean { private static Enforcer enforcer; private static final String modelpath = "model.conf"; @Override public void afterPropertiesSet() throws Exception { ClassPathResource classPathResource = new ClassPathResource(modelpath); enforcer = new Enforcer(classPathResource.getAbsolutePath(), jdbcAdapter); enforcer.savePolicy(); } /** * 是否存在命名受权规定 * * @param sub * @param obj * @param act * @return */ public boolean hasNamedPolicy(String sub, String obj, String act) { return enforcer.hasNamedPolicy("p", sub, obj, act); } /** * 是否匹配 * * @param match request * @return boolean */ public boolean policyMatch(Object... match) { return enforcer.enforce(match); } /** * 向以后策略增加角色继承规定 * * @param request * @return */ public boolean addGroupingPolicy(String... request) { boolean b = enforcer.addGroupingPolicy(request); savePolicy(); return b; } /** * 增加权限 * * @param policy request * @return boolean */ public boolean addPolicy(Policy policy) { boolean addPolicy = enforcer.addPolicy(policy.getSub(), policy.getObj(), policy.getAct()); savePolicy(); return addPolicy; } /** * 删除权限 * * @param policy request * @return boolean */ public boolean removePolicy(Policy policy) { boolean removePolicy = enforcer.removePolicy(policy.getSub(), policy.getObj(), policy.getAct()); savePolicy(); return removePolicy; } /** * 是否有此资源 * * @param sub * @param obj * @param act * @return */ public boolean hasPolicy(String sub, String obj, String act) { return enforcer.hasPolicy(sub, obj, act); }
更多api请参考官网:api文档
###6.定义拦截器,对登录用户的权限进行拦挡,并作出校验是否有此权限。
@Component@Slf4jpublic class MvcInterceptor implements HandlerInterceptor { private final EnforcerFactory EnforcerFactory; private final RedisUtil redisUtil; private final RoleService roleService; @Autowired public MvcInterceptor(EnforcerFactory enforcerFactory, RedisUtil redisUtil, RoleService roleService) { EnforcerFactory = enforcerFactory; this.redisUtil = redisUtil; this.roleService = roleService; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String path = request.getServletPath(); String method = request.getMethod(); log.info("用户ip:{},拜访门路:{},申请类型:{}", request.getRemoteAddr(), path, method); Cookie[] cookies = request.getCookies(); ParamCheck.getArrayCheck(cookies, "以后用户未登陆,请从新登陆。"); // 获取登录的cookie对象 Optional<Cookie> first = Arrays.stream(cookies).filter(w -> w.getName().equals(UserConstants.USER_LOGIN_COOKIE)).findFirst(); // 校验是否登录 if (!first.isPresent()) { throw new BaseException("用户未登录,请从新登录"); } // 获取到cookie Cookie cookie = first.get(); String key = String.format(UserConstants.USER_LOGIN_REDIS, cookie.getValue()); if (!redisUtil.hasKey(key)) { response.addCookie(CookieUtil.cleanCookie(cookie)); throw new BaseException("以后用户未登陆,请从新登陆"); } redisUtil.expire(key, 600); UserThreadLocal.setThreadLocal(JSON.parseObject((String) redisUtil.get(key), UserDO.class)); if (!EnforcerFactory.policyMatch(UserLocal.getRoleCode(), path, method)) { throw new BaseException("用户:" + UserLocal.getUserName() + ",无此权限"); } return true; }}