您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何實(shí)現(xiàn)網(wǎng)關(guān)Restful接口攔截”,在日常操作中,相信很多人在如何實(shí)現(xiàn)網(wǎng)關(guān)Restful接口攔截問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何實(shí)現(xiàn)網(wǎng)關(guān)Restful接口攔截”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
我們看下實(shí)際的案例,演示下這種場景。在 account-service
模塊下增加一個博客用戶管理功能,有如下的接口方法:
接口URL | HTTP方法 | 接口說明 |
---|---|---|
/blog/user | POST | 保存用戶 |
/blog/user/{id} | GET | 查詢用戶 |
/blog/user/{id} | DELETE | 刪除用戶 |
/blog/user/{id} | PUT | 更新用戶信息 |
然后我們在 sys_permission
表中添加2個用戶權(quán)限,再將其授予給用戶角色
在網(wǎng)關(guān)層的校驗(yàn)方法中可以看到已經(jīng)增加了2個權(quán)限
由于DELETE 和 PUT對應(yīng)的權(quán)限路徑都是 /blog/user/{id}
,這樣就是當(dāng)給用戶授予了查詢權(quán)限后此用戶也擁有了刪除和更新的權(quán)限。
看到這里大部分同學(xué)應(yīng)該想到了,要想實(shí)現(xiàn)Restful風(fēng)格的精細(xì)化權(quán)限管理單單通過URL路徑是不行的,需要搭配Method一起使用。
最關(guān)鍵的點(diǎn)就是「需要給權(quán)限表加上方法字段,然后在網(wǎng)關(guān)校驗(yàn)的時(shí)候即判斷請求路徑又匹配請求方法。」 實(shí)現(xiàn)步驟如下:
loadUserByUsername()
方法構(gòu)建用戶權(quán)限的時(shí)候?qū)?quán)限對應(yīng)的Method也拼接在權(quán)限上,關(guān)鍵代碼如下:@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
//獲取本地用戶
SysUser sysUser = sysUserMapper.selectByUserName(userName);
if(sysUser != null){
//獲取當(dāng)前用戶的所有角色
List<SysRole> roleList = sysRoleService.listRolesByUserId(sysUser.getId());
sysUser.setRoles(roleList.stream().map(SysRole::getRoleCode).collect(Collectors.toList()));
List<Integer> roleIds = roleList.stream().map(SysRole::getId).collect(Collectors.toList());
//獲取所有角色的權(quán)限
List<SysPermission> permissionList = sysPermissionService.listPermissionsByRoles(roleIds);
//拼接method
List<String> permissionUrlList = permissionList.stream()
.map(item -> "["+item.getMethod()+"]"+item.getUrl())
.collect(Collectors.toList());
sysUser.setPermissions(permissionUrlList);
//構(gòu)建oauth3的用戶
return buildUserDetails(sysUser);
}else{
throw new UsernameNotFoundException("用戶["+userName+"]不存在");
}
}
通過上面的代碼構(gòu)建的用戶權(quán)限如下:
[GET]/account-service/blog/user/{id}
[POST]/account-service/blog/user
可以通過代碼調(diào)試查看:
AccessManager#check()
,校驗(yàn)
[MEHOTD]RequestPath
格式@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> authenticationMono, AuthorizationContext authorizationContext) {
ServerWebExchange exchange = authorizationContext.getExchange();
ServerHttpRequest request = exchange.getRequest();
//請求資源
String requestPath = request.getURI().getPath();
//拼接method
String methodPath = "["+request.getMethod()+"]" + requestPath;
// 1. 對應(yīng)跨域的預(yù)檢請求直接放行
if(request.getMethod() == HttpMethod.OPTIONS){
return Mono.just(new AuthorizationDecision(true));
}
// 是否直接放行
if (permitAll(requestPath)) {
return Mono.just(new AuthorizationDecision(true));
}
return authenticationMono.map(auth -> new AuthorizationDecision(checkAuthorities(auth, methodPath)))
.defaultIfEmpty(new AuthorizationDecision(false));
}
校驗(yàn)方法 checkAuthorities()
:
private boolean checkAuthorities(Authentication auth, String requestPath) {
if(auth instanceof OAuth3Authentication){
OAuth3Authentication authentication = (OAuth3Authentication) auth;
String clientId = authentication.getOAuth3Request().getClientId();
log.info("clientId is {}",clientId);
//用戶的權(quán)限集合
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
return authorities.stream()
.map(GrantedAuthority::getAuthority)
//ROLE_開頭的為角色,需要過濾掉
.filter(item -> !item.startsWith(CloudConstant.ROLE_PREFIX))
.anyMatch(permission -> ANT_PATH_MATCHER.match(permission, requestPath));
}
return true;
}
這里還有另外一種方案,實(shí)現(xiàn)的原理跟上面差不多,只簡單提一下。
首先還是得在權(quán)限表中新增METHOD字段,這是必須的。
然后項(xiàng)目中使用的權(quán)限類是 SimpleGrantedAuthority
,這個只能存儲一個權(quán)限字段,我們可以自定義一個權(quán)限實(shí)體類,讓其可以存儲url 和 method。
@Data
public class MethodGrantedAuthority implements GrantedAuthority {
private String method;
private String url;
public MethodGrantedAuthority(String method, String url){
this.method = method;
this.url = url;
}
@Override
public String getAuthority() {
return "["+method+"]" + url;
}
}
在 UserDetailServiceImpl
中構(gòu)建用戶權(quán)限時(shí)使用自定義的 MethodGrantedAuthority
網(wǎng)關(guān)層校驗(yàn)的方法還是需要跟上面一樣,既校驗(yàn)Method 又 校驗(yàn) URL。
到此,關(guān)于“如何實(shí)現(xiàn)網(wǎng)關(guān)Restful接口攔截”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。