天天看點

jcasbin與springboot的整合

版本管理

包名 版本 備注
jcasbin Latest
springboot 2.x springboot版本,這個沒有太大的關系
JDK 1.8+ 基礎環境

#倉庫引入

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

整合過程

其實也可以讀取資料庫的角色權限配置。是以我們可以把關于資料庫的資訊提取出來,可以進行動态設定。

@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
           

讀取權限資訊進行初始化

我們要對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 + ];
  }
  
}

           

使用

權限控制

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() {
    
  }
 
}
           

添加删除權限

@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();
  }

           

也可以與其它架構整合