乐趣区

关于java:再见了-Shiro

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 仓库引入

<dependency>
    <groupId>org.casbin</groupId>
    <artifactId>jcasbin</artifactId>
    <version>1.1.0</version>
</dependency>
<dependency>
    <groupId>org.casbin</groupId>
    <artifactId>jdbc-adapter</artifactId>
    <version>1.1.0</version>
</dependency>

2、配置文件

jcasbin 把用户的角色、权限信息(拜访门路)搁置在配置文件里,而后通过输出流读取配置文件。次要有两个配置文件:model.conf 和 policy.csv。简略的应用 GitHub 里都讲了,在此就不再赘述了。

其实也能够读取数据库的角色权限配置。所以咱们能够把对于数据库的信息提取进去,能够进行动静设置。

@Configuration
@ConfigurationProperties(prefix = org.jcasbin)
public class EnforcerConfigProperties {
 
  private String url;
  
  private String driverClassName;
  
  private String username;
  
  private String password;
  
  private String modelPath;
 
  public String getUrl() {return url;}
 
  public void setUrl(String url) {this.url = url;}
 
  public String getDriverClassName() {return driverClassName;}
 
  public void setDriverClassName(String driverClassName) {this.driverClassName = driverClassName;}
 
  public String getUsername() {return username;}
 
  public void setUsername(String username) {this.username = username;}
 
  public String getPassword() {return password;}
 
  public void setPassword(String password) {this.password = password;}
 
  public String getModelPath() {return modelPath;}
 
  public void setModelPath(String modelPath) {this.modelPath = modelPath;}
 
  @Override
  public String toString() {
    return EnforcerConfigProperties [url= + url + , driverClassName= + driverClassName + , username=
        + username + , password= + password + , modelPath= + modelPath + ];
  }
  
}

这样咱们就能够在 application.properties 里进行相干配置了。model.conf 是固定的文件,之间复制过去放在新建的和 src 同级的文件夹下即可。policy.csv 的内容是能够从数据库读取的。

org.jcasbin.url=jdbc:mysql://localhost:3306/casbin?useSSL=false
org.jcasbin.driver-class-name=com.mysql.jdbc.Driver
org.jcasbin.username=root
org.jcasbin.password=root
org.jcasbin.model-path=conf/authz_model.conf

3、读取权限信息进行初始化

咱们要对 Enforcer 这个类初始化,加载配置文件里的信息。所以咱们写一个类实现 InitializingBean,在容器加载的时候就初始化这个类,不便后续的应用。

@Component
public class EnforcerFactory implements InitializingBean {
 
  private static Enforcer enforcer;
 
  @Autowired
  private EnforcerConfigProperties enforcerConfigProperties;
  private static EnforcerConfigProperties config;
  
  @Override
  public void afterPropertiesSet() throws Exception {
    config = enforcerConfigProperties;
    // 从数据库读取策略
    JDBCAdapter jdbcAdapter = new JDBCAdapter(config.getDriverClassName(),config.getUrl(),config.getUsername(),
                          config.getPassword(), true);
    enforcer = new Enforcer(config.getModelPath(), jdbcAdapter);
    enforcer.loadPolicy();//Load the policy from DB.}
  
  /**
   * 增加权限
   * @param policy
   * @return
   */
  public static boolean addPolicy(Policy policy){boolean addPolicy = enforcer.addPolicy(policy.getSub(),policy.getObj(),policy.getAct());
    enforcer.savePolicy();
    
    return addPolicy;
  }
  
  /**
   * 删除权限
   * @param policy
   * @return
   */
  public static boolean removePolicy(Policy policy){boolean removePolicy = enforcer.removePolicy(policy.getSub(),policy.getObj(),policy.getAct());
    enforcer.savePolicy();
    
    return removePolicy;
  }
  
  public static Enforcer getEnforcer(){return enforcer;}
  
}

在这个类里,咱们注入写好的配置类,而后转为动态的,在 afterPropertiesSet 办法里实例化 Enforcer 并加载 policy(策略,角色权限 /url 对应关系)。

同时又写了两个办法,用来增加和删除 policy,Policy 是自定的一个类,对官网应用的汇合 / 数组进行了封装。

public class Policy {
  /** 想要拜访资源的用户 或者角色 */
  private String sub;
  
  /** 将要拜访的资源,能够应用 * 作为通配符,例如 /user/* */
  private String obj;
  
  /** 用户对资源执行的操作。HTTP 办法,GET、POST、PUT、DELETE 等,能够应用 * 作为通配符 */
  private String act;
 
  public Policy() {super();
  }
  
  /**
   * 
   * @param sub 想要拜访资源的用户 或者角色
   * @param obj 将要拜访的资源,能够应用 * 作为通配符,例如 /user/*
   * @param act 用户对资源执行的操作。HTTP 办法,GET、POST、PUT、DELETE 等,能够应用 * 作为通配符
   */
  public Policy(String sub, String obj, String act) {super();
    this.sub = sub;
    this.obj = obj;
    this.act = act;
  }
 
  public String getSub() {return sub;}
 
  public void setSub(String sub) {this.sub = sub;}
 
  public String getObj() {return obj;}
 
  public void setObj(String obj) {this.obj = obj;}
 
  public String getAct() {return act;}
 
  public void setAct(String act) {this.act = act;}
 
  @Override
  public String toString() {return Policy [sub= + sub + , obj= + obj + , act= + act +];
  }
  
}

4、应用

1、权限管制

jcasbin 的权限管制非常简单,自定义一个过滤器,if 判断就能够搞定,没错,就这么简略。

@WebFilter(urlPatterns = /* , filterName = JCasbinAuthzFilter)
@Order(Ordered.HIGHEST_PRECEDENCE)// 执行程序,最高级别最先执行,int 从小到大
public class JCasbinAuthzFilter implements Filter {private static final Logger log = LoggerFactory.getLogger(JCasbinAuthzFilter.class);
 
  private static Enforcer enforcer;
 
  @Override
  public void init(FilterConfig filterConfig) throws ServletException { }
 
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
      throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        
        String user = request.getParameter(username);
        String path = request.getRequestURI();
        String method = request.getMethod();
 
        enforcer = EnforcerFactory.getEnforcer();
        if (path.contains(anon)) {chain.doFilter(request, response);
    }else if (enforcer.enforce(user, path, method)) {chain.doFilter(request, response);
    } else {log.info( 无权拜访);
      Map<String, Object> result = new HashMap<String, Object>();
            result.put(code, 1001);
            result.put(msg, 用户权限有余);
            result.put(data,null);
            response.setCharacterEncoding(UTF-8);
            response.setContentType(application/json);
            response.getWriter().write(JSONObject.toJSONString(result,SerializerFeature.WriteMapNullValue));
      }
    
  }
 
  @Override
  public void destroy() {}
 
}

次要是用 enforcer.enforce(user, path, method) 这个办法对用户、拜访资源、形式进行匹配。这里的逻辑能够依据本人的业务来实现。在这个过滤器之前还能够增加一个判断用户是否登录的过滤器。

2、增加删除权限

对于权限的操作,间接调用下面写好的 EnforcerFactory 里对应的办法即可。并且,能够达到同步的成果。就是不必重启服务器或者其余任何操作,增加或删除用户权限后,用户对应的拜访就会收到影响。

@PutMapping(/anon/role/per)
  public ResultBO<Object> addPer(){EnforcerFactory.addPolicy(new Policy(alice, /user/list, *));
    
    return ResultTool.success();}
  
  @DeleteMapping(/anon/role/per)
  public ResultBO<Object> deletePer(){EnforcerFactory.removePolicy(new Policy(alice, /user/list, *));
    
    return ResultTool.success();}

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 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版