close
關注我,回復關鍵字「spring」,
免費領取Spring學習資料。

來源:blog.csdn.net/WayneLee0809/article/details/85702551

前言

作為一名後台開發人員,權限這個名詞應該算是特別熟悉的了。就算是java里的類也有 public、private 等「權限」之分。之前項目里一直使用shiro作為權限管理的框架。說實話,shiro的確挺強大的,但是它也有很多不好的地方。shiro默認的登錄地址還是login.jsp,前後端分離模式使用shiro還要重寫好多類;手機端存儲用戶信息、保持登錄狀態等等,對shiro來說也是一個難題。

在分布式項目里,比如電商項目,其實不太需要明確的權限劃分,說白了,我認為沒必要做太麻煩的權限管理,一切從簡。何況shiro對於springCloud等各種分布式框架來說,簡直就是「災難」。每個子系統里都要寫點shiro的東西,慢慢的,越來越噁心。zuul網關就在這裡大顯身手了,控制用戶的登錄,鑑定用戶的權限等等。zuul網關控制用戶登錄,鑒權以後再詳說。以上拙見。

然後最近我發現了另一個權限框架jcasbin,雖然網上還沒有很多關於博客,但是我看了一會就可以使用了。

順手貼上github地址:https://github.com/casbin/jcasbin

一、準備

基於springboot1.5.10,但是和springboot關係不太大,所以版本可以忽略,用你熟悉的springboot版本就行。

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")publicclassEnforcerConfigProperties{privateStringurl;privateStringdriverClassName;privateStringusername;privateStringpassword;privateStringmodelPath;publicStringgetUrl(){returnurl;}publicvoidsetUrl(Stringurl){this.url=url;}publicStringgetDriverClassName(){returndriverClassName;}publicvoidsetDriverClassName(StringdriverClassName){this.driverClassName=driverClassName;}publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this.username=username;}publicStringgetPassword(){returnpassword;}publicvoidsetPassword(Stringpassword){this.password=password;}publicStringgetModelPath(){returnmodelPath;}publicvoidsetModelPath(StringmodelPath){this.modelPath=modelPath;}@OverridepublicStringtoString(){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=falseorg.jcasbin.driver-class-name=com.mysql.jdbc.Driverorg.jcasbin.username=rootorg.jcasbin.password=rootorg.jcasbin.model-path=conf/authz_model.conf二、讀取權限信息進行初始化

我們要對Enforcer這個類初始化,加載配置文件里的信息。所以我們寫一個類實現InitializingBean,在容器加載的時候就初始化這個類,方便後續的使用。

@ComponentpublicclassEnforcerFactoryimplementsInitializingBean{privatestaticEnforcerenforcer;@AutowiredprivateEnforcerConfigPropertiesenforcerConfigProperties;privatestaticEnforcerConfigPropertiesconfig;@OverridepublicvoidafterPropertiesSet()throwsException{config=enforcerConfigProperties;//從數據庫讀取策略JDBCAdapterjdbcAdapter=newJDBCAdapter(config.getDriverClassName(),config.getUrl(),config.getUsername(),config.getPassword(),true);enforcer=newEnforcer(config.getModelPath(),jdbcAdapter);enforcer.loadPolicy();//LoadthepolicyfromDB.}/***添加權限*@parampolicy*@return*/publicstaticbooleanaddPolicy(Policypolicy){booleanaddPolicy=enforcer.addPolicy(policy.getSub(),policy.getObj(),policy.getAct());enforcer.savePolicy();returnaddPolicy;}/***刪除權限*@parampolicy*@return*/publicstaticbooleanremovePolicy(Policypolicy){booleanremovePolicy=enforcer.removePolicy(policy.getSub(),policy.getObj(),policy.getAct());enforcer.savePolicy();returnremovePolicy;}publicstaticEnforcergetEnforcer(){returnenforcer;}}

在這個類里,我們注入寫好的配置類,然後轉為靜態的,在afterPropertiesSet方法裡實例化Enforcer並加載policy(策略,角色權限/url對應關係)。

同時又寫了兩個方法,用來添加和刪除policy,Policy是自定的一個類,對官方使用的集合/數組進行了封裝。

publicclassPolicy{/**想要訪問資源的用戶或者角色*/privateStringsub;/**將要訪問的資源,可以使用*作為通配符,例如/user/**/privateStringobj;/**用戶對資源執行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用*作為通配符*/privateStringact;publicPolicy(){super();}/****@paramsub想要訪問資源的用戶或者角色*@paramobj將要訪問的資源,可以使用*作為通配符,例如/user/**@paramact用戶對資源執行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用*作為通配符*/publicPolicy(Stringsub,Stringobj,Stringact){super();this.sub=sub;this.obj=obj;this.act=act;}publicStringgetSub(){returnsub;}publicvoidsetSub(Stringsub){this.sub=sub;}publicStringgetObj(){returnobj;}publicvoidsetObj(Stringobj){this.obj=obj;}publicStringgetAct(){returnact;}publicvoidsetAct(Stringact){this.act=act;}@OverridepublicStringtoString(){return"Policy[sub="+sub+",obj="+obj+",act="+act+"]";}}三、使用1、權限控制

jcasbin的權限控制非常簡單,自定義一個過濾器,if判斷就可以搞定,沒錯,就這麼簡單。

@WebFilter(urlPatterns="/*",filterName="JCasbinAuthzFilter")@Order(Ordered.HIGHEST_PRECEDENCE)//執行順序,最高級別最先執行,int從小到大publicclassJCasbinAuthzFilterimplementsFilter{privatestaticfinalLoggerlog=LoggerFactory.getLogger(JCasbinAuthzFilter.class);privatestaticEnforcerenforcer;@Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{}@OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainchain)throwsIOException,ServletException{HttpServletRequestrequest=(HttpServletRequest)servletRequest;HttpServletResponseresponse=(HttpServletResponse)servletResponse;Stringuser=request.getParameter("username");Stringpath=request.getRequestURI();Stringmethod=request.getMethod();enforcer=EnforcerFactory.getEnforcer();if(path.contains("anon")){chain.doFilter(request,response);}elseif(enforcer.enforce(user,path,method)){chain.doFilter(request,response);}else{log.info("無權訪問");Map<String,Object>result=newHashMap<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));}}@Overridepublicvoiddestroy(){}}

主要是用enforcer.enforce(user, path, method)這個方法對用戶、訪問資源、方式進行匹配。這裡的邏輯可以根據自己的業務來實現。在這個過濾器之前還可以添加一個判斷用戶是否登錄的過濾器。

2、添加刪除權限

對於權限的操作,直接調用上面寫好的EnforcerFactory里對應的方法即可。並且,可以達到同步的效果。就是不用重啟服務器或者其他任何操作,添加或刪除用戶權限後,用戶對應的訪問就會收到影響。

@PutMapping("/anon/role/per")publicResultBO<Object>addPer(){EnforcerFactory.addPolicy(newPolicy("alice","/user/list","*"));returnResultTool.success();}@DeleteMapping("/anon/role/per")publicResultBO<Object>deletePer(){EnforcerFactory.removePolicy(newPolicy("alice","/user/list","*"));returnResultTool.success();}寫在後面的話

其實可以把jcasbin和SpringCloud的zuul結合來實現用戶的統一登錄和權限控制。自定義一個過濾器繼承ZuulFilter即可,其他地方基本沒啥區別。


END


SSO 單點登錄和 OAuth2.0 的區別和理解
使用 Jenkins 持續集成的一些經驗總結
Spring Boot 項目如何按模塊進行拆分?
雲原生時代的 Java 虛擬機

關注後端面試那些事,回復【2022面經】

獲取最新大廠Java面經


最後重要提示:高質量的技術交流群,限時免費開放,今年抱團最重要。想進群的,關注SpringForAll社區,回復關鍵詞:加群,拉你進群。




點擊這裡領取2022大廠面經
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()