日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

php中引入shiro,基于shiro的自定义注解的扩展-图文详解

發布時間:2024/9/27 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php中引入shiro,基于shiro的自定义注解的扩展-图文详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基于shiro的自定義注解的擴展

這里我們主要采取了shiro的自定義注解的方案。本篇文章主要解決以下的問題。如何通過邏輯進行頁面與api接口的關聯。

shiro的自身注解的用法。

如何編寫自定義注解。

如何通過邏輯進行頁面與api接口的關聯

在表與表的結構關系中,頁面和接口表最終都是與權限表進行的關聯(詳情請查看我的上一篇文章《權限設計的雜談》)。

我們現在希望用另一種方案去替代他,實現一個低成本同時兼顧一定程度的權限控制。這里我們引入兩個概念。業務模塊,操作類型。業務模塊概念:將系統中的業務模塊抽象成一種數據,我們可以用字符串的形式去表示,例如:角色管理對應是role-manage、用戶管理對應是user-manage等等。我們將系統中所存在的業務模塊通過“最小特權原則”進行劃分,最終形成一批可分配的數據。

使用原則:api接口和頁面以及功能從本質上來說,都和業務模塊有邏輯關系,于是,我們可以對api接口與頁面(以及功能點)進行邏輯匹配,來判斷頁面與接口的關系。

操作類型概念:將系統中的所有的操作類型抽象成一種數據,我們也可以用字符串的形式去表示,例如:新增對應的是add、分配對應的是allot等等。我們將系統中所有的操作類型根據業務模塊通過“數據許可證”進行劃分,最終形成一批可分配的數據。

使用原則:頁面是展示,功能點是動作,而接口是最終動作的資源提供,通過“業務模塊”確定了調取的資源,通過“操作類型”確定了資源的使用方式。通過兩者可以大致無誤的判斷頁面的功能點觸發的接口是否在鑒權之內。

現在提出了這兩個概念,他們最終的實際的使用方式是什么,我們先從以下幾個角度去思考一下。數據庫中的頁面表或的api接口表中的數據就是真實有效嗎?

頁面或接口的實際使用,是以功能存在為前提,還是以數據庫表中的數據存在為前提。

權限結構中,“控制對象”的存儲只有數據庫這一種途徑嗎?

我們從結論出發來看這幾個問題,首先“控制對象”的存儲除了在數據庫中也可以代碼中,也可以在配置文件中,并不一定非得在數據庫;那么接著回答第二個問題,當數據庫存在的接口信息,而服務端并沒有開發這個接口的時候,數據庫的信本身就有問題,亦或者,數據庫里新增的接口必定是服務端上已經部署的接口才能生效;接著就是第一個問題,那么數據庫中關于“控制對象”的表中的數據并不一定是真實有效的。所以我們可以得出以下的解決方案我們可以在接口上用注解的形式補充“業務模塊”和“操作類型”的數據信息,這兩類信息都可以存于常量類中,

在數據庫添加創建頁面表結構和頁面功能表結構的時候,添加“業務模塊”和“操作類型”字段。

可以將“業務模塊”和“操作類型”的信息存于數據庫的字典表中。

模塊的新增或操作的新增,必定帶來了接口的新增,那么就會帶來一次系統部署活動,這個運維成本是無法減少的,并不能通過表結構來減少。

但是這種方案僅適用于非強控制接口型的項目,在強控制型的接口項目仍然要將頁面與接口進行綁定,雖然這會帶來巨大的運維成本。另外也可以通過接口路由規則進行劃分,例如:/api/page/xxxx/(僅對頁面使用),/api/mobile/xxxxx(僅對移動端使用)將僅供頁面使用的接口進行分類,這類接口僅做認證不做授權,也可以達到目的。

shiro的自身注解的用法

通過一個理論上的思路認可之后,剩下的則是付諸技術上的實踐,我們這邊采用的是Apache Shiro的安全框架,在Spring Boot的環境下應用。簡要說明以下幾個shiro的注解。注解名作用@RequiresAuthentication作用于的類、方法、實例上。調用時,當前的subject是必須經過了認證的。

@RequiresGuest作用于的類、方法、實例上。調用時,subject可以是guest狀態。

@RequiresPermissions作用于的類、方法、實例上。調用時,需要判斷suject中是否包含當前接口中的Permission(權限信息)。

@RequiresRoles作用于的類、方法、實例上。調用時,需要判斷subject中是否包含當前接口中的Role(角色信息)。

@RequiresUser作用于的類、方法、實例上。調用時,需要判斷subject中是否當前應用中的用戶。/**

* 1.當前接口需要經過"認證"過程

* @return

*/

@RequestMapping(value = "/info",method = RequestMethod.GET)

@RequiresAuthentication

public String test(){

return "恭喜你,拿到了參數信息";

}

/**

* 2.1.當前接口需要經過權限校驗(需包含 角色的查詢 或 菜單的查詢)

* @return

*/

@RequestMapping(value = "/info",method = RequestMethod.GET)

@RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)

public String test(){

return "恭喜你,拿到了參數信息";

}

/**

* 2.2.當前接口需要經過權限校驗(需包含 角色的查詢 與 菜單的查詢)

* @return

*/

@RequestMapping(value = "/info",method = RequestMethod.GET)

@RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)

public String test(){

return "恭喜你,拿到了參數信息";

}

/**

* 3.1.當前接口需要經過角色校驗(需包含admin的角色)

* @return

*/

@RequestMapping(value = "/info",method = RequestMethod.GET)

@RequiresRoles(value={"admin"})

public String test(){

return "恭喜你,拿到了參數信息";

}

/**

* 3.2.當前接口需要經過角色與權限的校驗(需包含admin的角色,以及角色的查詢 或 菜單的查詢)

* @return

*/

@RequestMapping(value = "/info",method = RequestMethod.GET)

@RequiresRoles(value={"admin"})

@RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR)

public String test(){

return "恭喜你,拿到了參數信息";

}

在我們的實際使用過程中,實際上只需要使用@RequiresPermissions和@RequiresAuthentication就可以了這一個注解就可以了,在上一小節的結尾,我們采取了業務模塊與操作的結合方案來解耦頁面和api接口的關系,和apache Shiro的這種方式正好一致。但是@RequiresRoles這個我們盡可能不采用,因為角色的組合形式太多,角色名沒有辦法在接口中具象唯一化(很難指定接口歸某個角色調用,但是一定能知道接口歸屬于某些業務模塊的某些操作。)

現在我們來回顧一下整個運轉的流程。

如何編寫自定義注解

但是僅僅是擁有shiro中的這5個注解肯定是不夠使用的。在實際的使用過程中,根據需求,我們會在權限認證中加入我們自己特有的業務邏輯的,我們為了便捷則可以采用自定義注解的方式進行使用。這種方法不僅僅適用于Apache Shiro,很多其他的框架如:Hibernate Validator、SpringMVC、甚至我們可以寫一套校驗體系,在aop中去驗證權限,這都是沒問題的。所以自定義注解的作用很廣。但是在這里,我僅僅基于shiro的來實現適用于它的自定義注解。定義注解類/**

* 用于認證的接口的注解,組合形式默認是“或”的關系

*/

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface Auth {

/**

* 業務模塊

* @return

*/

String[] module();

/**

* 操作類型

*/

String[] action();

}定義注解的處理類/**

* Auth注解的操作類

*/

public class AuthHandler extends AuthorizingAnnotationHandler {

public AuthHandler() {

//寫入注解

super(Auth.class);

}

@Override

public void assertAuthorized(Annotation a) throws AuthorizationException {

if (a instanceof Auth) {

Auth annotation = (Auth) a;

String[] module = annotation.module();

String[] action = annotation.action();

//1.獲取當前主題

Subject subject = this.getSubject();

//2.驗證是否包含當前接口的權限有一個通過則通過

boolean hasAtLeastOnePermission = false;

for(String m:module){

for(String ac:action){

//使用hutool的字符串工具類

String permission = StrFormatter.format("{}:{}",m,ac);

if(subject.isPermitted(permission)){

hasAtLeastOnePermission=true;

break;

}

}

}

if(!hasAtLeastOnePermission){

throw new AuthorizationException("沒有訪問此接口的權限");

}

}

}

}定義shiro攔截處理類/**

* 攔截器

*/

public class AuthMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {

public AuthMethodInterceptor() {

super(new AuthHandler());

}

public AuthMethodInterceptor(AnnotationResolver resolver) {

super(new AuthHandler(), resolver);

}

@Override

public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {

// 驗證權限

try {

((AuthHandler) this.getHandler()).assertAuthorized(getAnnotation(mi));

} catch (AuthorizationException ae) {

if (ae.getCause() == null) {

ae.initCause(new AuthorizationException("當前的方法沒有通過鑒權: " + mi.getMethod()));

}

throw ae;

}

}

}定義shiro的aop切面類/**

* shiro的aop切面

*/

public class AuthAopInterceptor extends AopAllianceAnnotationsAuthorizingMethodInterceptor {

public AuthAopInterceptor() {

super();

// 添加自定義的注解攔截器

this.methodInterceptors.add(new AuthMethodInterceptor(new SpringAnnotationResolver()));

}

}定義shiro的自定義注解啟動類/**

* 啟動自定義注解

*/

public class ShiroAdvisor extends AuthorizationAttributeSourceAdvisor {

public ShiroAdvisor() {

// 這里可以添加多個

setAdvice(new AuthAopInterceptor());

}

@SuppressWarnings({"unchecked"})

@Override

public boolean matches(Method method, Class targetClass) {

Method m = method;

if (targetClass != null) {

try {

m = targetClass.getMethod(m.getName(), m.getParameterTypes());

return this.isFrameAnnotation(m);

} catch (NoSuchMethodException ignored) {

}

}

return super.matches(method, targetClass);

}

private boolean isFrameAnnotation(Method method) {

return null != AnnotationUtils.findAnnotation(method, Auth.class);

}

}總體的思路順序:定義注解類(定義業務可使用的變量)->定義注解處理類(通過注解中的變量做業務邏輯處理)->定義注解的攔截器->定義aop的切面類->最后定義shiro的自定義注解啟用類。其他的自定義的注解的編寫思路和這個也是類似的。

相關推薦:

總結

以上是生活随笔為你收集整理的php中引入shiro,基于shiro的自定义注解的扩展-图文详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。