版本管理
包名 | 版本 | 備注 |
---|---|---|
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();
}