JwtPermission-Java Web權限控制框架

JwtPermission

基於token驗證的Java Web權限控制框架

,使用jjwt,支持redis和db多種存儲方式,支持統一身份認證(單點登錄)功能,可用於前後端分離項目,功能完善、使用簡單、易於擴展。

支持與SpringBoot集成,與SpringMvc的集成。

為什麼要開發JwtPermission:

  在平常工作中一直使用shiro作為權限框架框架,主要做管理平臺之類的項目,項目是前後端不分離的,但是很多項目都會有APP、公眾號、小程序之類的,我們的主要功能在Web上,APP、公眾號、小程序只是佔了極小一部分的功能,整個項目也不是大型項目,人手也有限,所以整個項目只做了一個工程,對移動端的接口又需要使用基於token的RESTful風格,所以開發了JwtPermission權限框架,可以跟shiro共存於一個工程中,shiro排除攔截/api/開頭的路徑,JwtPermission只攔截/api/開頭的路徑,互不影響,整個項目一個工程也方便上線部署、後期維護,因為是外包項目,一個項目最多兩個月就結束了,沒有重大線上bug及改動是不會再管的了。

應用場景:

  • (1) 作為移動應用的接口權限控制 ,如果你的Web項目的權限框架是前後端不分離的(基於session),同時又需要對移動端、開放接口等提供RESTful接口及token權限控制,可將JwtPermission很方便的集成在你的項目中,只用於對接口進行權限控制及token簽發等。
  • (2) 用於前後端分離項目的權限控制,在前後端分離的項目中使用像shiro這類基於session的權限框架是不合適的,當然網上有很多shiro集成jwt的文章,個人感覺對shiro的改造太大了,最好是使用oauth2.0、spring security-oauth2這樣的權限框架,但是security的學習成本還是比較高的,oauth2適合做微服務之類的大型項目,如果你的項目是小型項目、單體項目,可以嘗試用JwtPermission作為你的權限控制框架,簡單、靈活、極易上手。

集成

與SpringBoot集成:

1.導入

<code><dependency>
<groupid>com.github.whvcse/<groupid>
<artifactid>jwtp-spring-boot-starter/<artifactid>
<version>3.1.1/<version>
/<dependency>/<code>

2.加註解

在Application啟動類上面加入@EnableJwtPermission註解。

3.配置

<code>## 0是 redisTokenStore ,1是 jdbcTokenStore ,默認是0
jwtp.store-type=0

## 攔截路徑,默認是/**
jwtp.path=/**

## 排除攔截路徑,默認無
jwtp.exclude-path=/login

## 單個用戶最大token數,默認-1不限制
jwtp.max-token=10

## url自動對應權限方式,0 簡易模式,1 RESTful模式
# jwtp.url-perm-type=0

## 自定義查詢用戶權限的sql
# jwtp.find-permissions-sql=SELECT authority FROM sys_user_authorities WHERE user_id = ?

## 自定義查詢用戶角色的sql
# jwtp.find-roles-sql=SELECT role_id FROM sys_user_role WHERE user_id = ?

## 日誌級別設置debug可以輸出詳細信息
logging.level.org.wf.jwtp=DEBUG/<code>

如果使用jdbcTokenStore需要導入框架提供的sql腳本,如果使用redisTokenStore,需要集成好redis


登錄簽發token

<code>@RestController
public class LoginController {
@Autowired
private TokenStore tokenStore;

@PostMapping("/token")
public Map token(String account, String password) {

// 你的驗證邏輯
// ......
// 簽發token
Token token = tokenStore.createNewToken(userId, permissions, roles, expire);
System.out.println("access_token:" + token.getAccessToken());
}
}/<code>

createNewToken方法參數說明:

  • userId        token載體,建議為用戶id
  • permissions      權限列表
  • roles         角色列表
  • expire        token過期時間(單位秒)

使用註解或代碼限制權限

1.使用註解的方式:

<code>// 需要有system權限才能訪問
@RequiresPermissions("system")

// 需要有system和front權限才能訪問,logical可以不寫,默認是AND
@RequiresPermissions(value={"system","front"}, logical=Logical.AND)

// 需要有system或front權限才能訪問
@RequiresPermissions(value={"system","front"}, logical=Logical.OR)

// 需要有admin或user角色才能訪問
@RequiresRoles(value={"admin","user"}, logical=Logical.OR)/<code>

註解加在Controller的方法或類上面。

2.使用代碼的方式:

<code>//是否有system權限
SubjectUtil.hasPermission(request, "system");

//是否有system或者front權限
SubjectUtil.hasPermission(request, new String[]{"system","front"}, Logical.OR);

//是否有admin或者user角色
SubjectUtil.hasRole(request, new String[]{"admin","user"}, Logical.OR)/<code>

異常處理

JwtPermistion在token驗證失敗和沒有權限的時候會拋出異常:

異常 描述 錯誤信息 ErrorTokenException token驗證失敗 錯誤信息“身份驗證失敗”,錯誤碼401 ExpiredTokenException token已經過期 錯誤信息“登錄已過期”,錯誤碼402 UnauthorizedException 沒有權限 錯誤信息“沒有訪問權限”,錯誤碼403

建議使用異常處理器來捕獲異常並返回json數據:

<code>@ControllerAdvice
public class ExceptionHandler {

@ResponseBody
@ExceptionHandler(Exception.class)
public Map<string> errorHandler(Exception ex) {
Map<string> map = new HashMap<>();
// 根據不同錯誤獲取錯誤信息
if (ex instanceof TokenException) {

map.put("code", ((TokenException) ex).getCode());
map.put("msg", ex.getMessage());
} else {
map.put("code", 500);
map.put("msg", ex.getMessage());
ex.printStackTrace();
}
return map;
}
}/<string>/<string>/<code>

更多用法

1.使用註解忽略驗證

在Controller的方法或類上面添加@Ignore註解可排除框架攔截,即表示調用接口不用傳遞access_token了。

2.自定義查詢角色和權限的sql

如果是在簽發token的時候指定權限和角色,不重新獲取token,不主動更新權限,權限和角色不會實時更新, 可以配置自定義查詢角色和權限的sql來實時查詢用戶的權限和角色:

<code>## 自定義查詢用戶權限的sql
jwtp.find-permissions-sql=SELECT authority FROM sys_user_authorities WHERE user_id = ?

## 自定義查詢用戶角色的sql
jwtp.find-roles-sql=SELECT role_id FROM sys_user_role WHERE user_id = ?/<code>

3.url自動匹配權限

如果不想每個接口都加@RequiresPermissions註解來控制權限,可以配置url自動匹配權限:

<code>## url自動對應權限方式,0 簡易模式,1 RESTful模式
jwtp.url-perm-type=0/<code>

RESTful模式(請求方式:url):post:/api/login

簡易模式(url):/api/login

配置了自動匹配也可以同時使用註解,註解優先級高於自動匹配,你還可以藉助Swagger自動掃描所有接口生成權限到數據庫權限表中

4.獲取當前的用戶信息

<code>// 正常可以這樣獲取
Token token = SubjectUtil.getToken(request);

// 對於排除攔截的接口可以這樣獲取
Token token = SubjectUtil.parseToken(request);/<code>

5.主動讓token失效:

<code>// 移除用戶的某個token
tokenStore.removeToken(userId, access_token);

// 移除用戶的全部token
tokenStore.removeTokensByUserId(userId);/<code>

6.更新角色和權限列表

修改了用戶的角色和權限需要同步更新框架中的角色和權限:

<code>// 更新用戶的角色列表
tokenStore.updateRolesByUserId(userId, roles);


// 更新用戶的權限列表
tokenStore.updatePermissionsByUserId(userId, permissions);/<code>

前端傳遞token

放在參數裡面用access_token傳遞:

<code>$.get("/xxx", { access_token: token }, function(data) {

});/<code>

放在header裡面用Authorization、Bearer傳遞:

<code>$.ajax({
url: "/xxx",
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", 'Bearer '+ token);
},
success: function(data){ }
});/<code>

源碼地址:https://gitee.com/whvse/JwtPermission

開發文檔:https://gitee.com/whvse/JwtPermission/wikis/pages


分享到:


相關文章: