再见了 Shiro!

打印 上一主题 下一主题

主题 868|帖子 868|积分 2604

1、前言

作为一名后台开发人员,权限这个名词应该算是特别熟悉的了。就算是java里的类也有 public、private 等“权限”之分。之前项目里一直使用shiro作为权限管理的框架。说实话,shiro的确挺强大的,但是它也有很多不好的地方。shiro默认的登录地址还是login.jsp,前后端分离模式使用shiro还要重写好多类;手机端存储用户信息、保持登录状态等等,对shiro来说也是一个难题。
在分布式项目里,比如电商项目,其实不太需要明确的权限划分,说白了,我认为没必要做太麻烦的权限管理,一切从简。何况shiro对于springCloud等各种分布式框架来说,简直就是“灾难”。每个子系统里都要写点shiro的东西,慢慢的,越来越恶心。zuul网关就在这里大显身手了,控制用户的登录,鉴定用户的权限等等。zuul网关控制用户登录,鉴权以后再详说。以上拙见。
然后最近我发现了另一个权限框架jcasbin,虽然网上还没有很多关于博客,但是我看了一会就可以使用了。
github地址:https://github.com/casbin/jcasbin
2、准备

Spring Boot 基础就不介绍了,推荐看这个实战项目:
https://github.com/javastacks/spring-boot-best-practice
1、mavan仓库引入
  1. <dependency>
  2.     <groupId>org.casbin</groupId>
  3.     <artifactId>jcasbin</artifactId>
  4.     <version>1.1.0</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.casbin</groupId>
  8.     <artifactId>jdbc-adapter</artifactId>
  9.     <version>1.1.0</version>
  10. </dependency>
复制代码
2、配置文件
jcasbin把用户的角色、权限信息(访问路径)放置在配置文件里,然后通过输入流读取配置文件。主要有两个配置文件:model.conf 和 policy.csv。简单的使用GitHub里都讲了,在此就不再赘述了。
其实也可以读取数据库的角色权限配置。所以我们可以把关于数据库的信息提取出来,可以进行动态设置。
  1. @Configuration
  2. @ConfigurationProperties(prefix = org.jcasbin)
  3. public class EnforcerConfigProperties {
  4.   private String url;
  5.   
  6.   private String driverClassName;
  7.   
  8.   private String username;
  9.   
  10.   private String password;
  11.   
  12.   private String modelPath;
  13.   public String getUrl() {
  14.     return url;
  15.   }
  16.   public void setUrl(String url) {
  17.     this.url = url;
  18.   }
  19.   public String getDriverClassName() {
  20.     return driverClassName;
  21.   }
  22.   public void setDriverClassName(String driverClassName) {
  23.     this.driverClassName = driverClassName;
  24.   }
  25.   public String getUsername() {
  26.     return username;
  27.   }
  28.   public void setUsername(String username) {
  29.     this.username = username;
  30.   }
  31.   public String getPassword() {
  32.     return password;
  33.   }
  34.   public void setPassword(String password) {
  35.     this.password = password;
  36.   }
  37.   public String getModelPath() {
  38.     return modelPath;
  39.   }
  40.   public void setModelPath(String modelPath) {
  41.     this.modelPath = modelPath;
  42.   }
  43.   @Override
  44.   public String toString() {
  45.     return EnforcerConfigProperties [url= + url + , driverClassName= + driverClassName + , username=
  46.         + username + , password= + password + , modelPath= + modelPath + ];
  47.   }
  48.   
  49. }
复制代码
这样我们就可以在application.properties里进行相关配置了。model.conf是固定的文件,之间复制过来放在新建的和src同级的文件夹下即可。policy.csv的内容是可以从数据库读取的。
  1. org.jcasbin.url=jdbc:mysql://localhost:3306/casbin?useSSL=false
  2. org.jcasbin.driver-class-name=com.mysql.jdbc.Driver
  3. org.jcasbin.username=root
  4. org.jcasbin.password=root
  5. org.jcasbin.model-path=conf/authz_model.conf
复制代码
3、读取权限信息进行初始化

我们要对Enforcer这个类初始化,加载配置文件里的信息。所以我们写一个类实现InitializingBean,在容器加载的时候就初始化这个类,方便后续的使用。
  1. @Component
  2. public class EnforcerFactory implements InitializingBean {
  3.   private static Enforcer enforcer;
  4.   @Autowired
  5.   private EnforcerConfigProperties enforcerConfigProperties;
  6.   private static EnforcerConfigProperties config;
  7.   
  8.   @Override
  9.   public void afterPropertiesSet() throws Exception {
  10.     config = enforcerConfigProperties;
  11.     //从数据库读取策略
  12.     JDBCAdapter jdbcAdapter = new JDBCAdapter(config.getDriverClassName(),config.getUrl(),config.getUsername(),
  13.                           config.getPassword(), true);
  14.     enforcer = new Enforcer(config.getModelPath(), jdbcAdapter);
  15.     enforcer.loadPolicy();//Load the policy from DB.
  16.   }
  17.   
  18.   /**
  19.    * 添加权限
  20.    * @param policy
  21.    * @return
  22.    */
  23.   public static boolean addPolicy(Policy policy){
  24.     boolean addPolicy = enforcer.addPolicy(policy.getSub(),policy.getObj(),policy.getAct());
  25.     enforcer.savePolicy();
  26.    
  27.     return addPolicy;
  28.   }
  29.   
  30.   /**
  31.    * 删除权限
  32.    * @param policy
  33.    * @return
  34.    */
  35.   public static boolean removePolicy(Policy policy){
  36.     boolean removePolicy = enforcer.removePolicy(policy.getSub(),policy.getObj(),policy.getAct());
  37.     enforcer.savePolicy();
  38.    
  39.     return removePolicy;
  40.   }
  41.   
  42.   public static Enforcer getEnforcer(){
  43.     return enforcer;
  44.   }
  45.   
  46. }
复制代码
在这个类里,我们注入写好的配置类,然后转为静态的,在afterPropertiesSet方法里实例化Enforcer并加载policy(策略,角色权限/url对应关系)。
同时又写了两个方法,用来添加和删除policy,Policy是自定的一个类,对官方使用的集合/数组进行了封装。
  1. public class Policy {
  2.   /**想要访问资源的用户 或者角色*/
  3.   private String sub;
  4.   
  5.   /**将要访问的资源,可以使用 * 作为通配符,例如/user/* */
  6.   private String obj;
  7.   
  8.   /**用户对资源执行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用 * 作为通配符*/
  9.   private String act;
  10.   public Policy() {
  11.     super();
  12.   }
  13.   
  14.   /**
  15.    *
  16.    * @param sub 想要访问资源的用户 或者角色
  17.    * @param obj 将要访问的资源,可以使用 * 作为通配符,例如/user/*
  18.    * @param act 用户对资源执行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用 * 作为通配符
  19.    */
  20.   public Policy(String sub, String obj, String act) {
  21.     super();
  22.     this.sub = sub;
  23.     this.obj = obj;
  24.     this.act = act;
  25.   }
  26.   public String getSub() {
  27.     return sub;
  28.   }
  29.   public void setSub(String sub) {
  30.     this.sub = sub;
  31.   }
  32.   public String getObj() {
  33.     return obj;
  34.   }
  35.   public void setObj(String obj) {
  36.     this.obj = obj;
  37.   }
  38.   public String getAct() {
  39.     return act;
  40.   }
  41.   public void setAct(String act) {
  42.     this.act = act;
  43.   }
  44.   @Override
  45.   public String toString() {
  46.     return Policy [sub= + sub + , obj= + obj + , act= + act + ];
  47.   }
  48.   
  49. }
复制代码
4、使用

1、权限控制

jcasbin的权限控制非常简单,自定义一个过滤器,if判断就可以搞定,没错,就这么简单。
  1. @WebFilter(urlPatterns = /* , filterName = JCasbinAuthzFilter)
  2. @Order(Ordered.HIGHEST_PRECEDENCE)//执行顺序,最高级别最先执行,int从小到大
  3. public class JCasbinAuthzFilter implements Filter {
  4.   
  5.   private static final Logger log = LoggerFactory.getLogger(JCasbinAuthzFilter.class);
  6.   private static Enforcer enforcer;
  7.   @Override
  8.   public void init(FilterConfig filterConfig) throws ServletException {
  9.   }
  10.   @Override
  11.   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
  12.       throws IOException, ServletException {
  13.     HttpServletRequest request = (HttpServletRequest) servletRequest;
  14.         HttpServletResponse response = (HttpServletResponse) servletResponse;
  15.         
  16.         String user = request.getParameter(username);
  17.         String path = request.getRequestURI();
  18.         String method = request.getMethod();
  19.         enforcer = EnforcerFactory.getEnforcer();
  20.         if (path.contains(anon)) {
  21.           chain.doFilter(request, response);
  22.     }else if (enforcer.enforce(user, path, method)) {
  23.       chain.doFilter(request, response);
  24.     } else {
  25.       log.info(无权访问);
  26.       Map<String, Object> result = new HashMap<String, Object>();
  27.             result.put(code, 1001);
  28.             result.put(msg, 用户权限不足);
  29.             result.put(data,null);
  30.             response.setCharacterEncoding(UTF-8);
  31.             response.setContentType(application/json);
  32.             response.getWriter().write(JSONObject.toJSONString(result,SerializerFeature.WriteMapNullValue));
  33.       }
  34.    
  35.   }
  36.   @Override
  37.   public void destroy() {
  38.    
  39.   }
  40. }
复制代码
主要是用enforcer.enforce(user, path, method)这个方法对用户、访问资源、方式进行匹配。这里的逻辑可以根据自己的业务来实现。在这个过滤器之前还可以添加一个判断用户是否登录的过滤器。
2、添加删除权限

对于权限的操作,直接调用上面写好的EnforcerFactory里对应的方法即可。并且,可以达到同步的效果。就是不用重启服务器或者其他任何操作,添加或删除用户权限后,用户对应的访问就会收到影响。
  1. @PutMapping(/anon/role/per)
  2.   public ResultBO<Object> addPer(){
  3.    
  4.     EnforcerFactory.addPolicy(new Policy(alice, /user/list, *));
  5.    
  6.     return ResultTool.success();
  7.   }
  8.   
  9.   @DeleteMapping(/anon/role/per)
  10.   public ResultBO<Object> deletePer(){
  11.    
  12.     EnforcerFactory.removePolicy(new Policy(alice, /user/list, *));
  13.    
  14.     return ResultTool.success();
  15.   }
复制代码
5、最后

其实可以把jcasbin和SpringCloud的zuul结合来实现用户的统一登录和权限控制。自定义一个过滤器继承ZuulFilter即可,其他地方基本没啥区别。这个以后再写。
版权声明:本文为CSDN博主「红藕香残玉簟秋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/WayneLee0809/article/details/85702551
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小小小幸运

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表