## 1、前言 作為一名後臺開發人員,許可權這個名詞應該算是特別熟悉的了。就算是java里的類也有 public、private 等“許可權”之分。之前項目里一直使用shiro作為許可權管理的框架。說實話,shiro的確挺強大的,但是它也有很多不好的地方。shiro預設的登錄地址還是login.jsp,前 ...
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 基礎就不介紹了,推薦看這個實戰項目:
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最新版)
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
覺得不錯,別忘了隨手點贊+轉發哦!