大家好,我是不才陳某~
在碼猿慢病云管理系統(tǒng)采用的是Spring Cloud 集成Spring Security OAuth2的方式實(shí)現(xiàn)認(rèn)證、鑒權(quán),其中涉及到的一個(gè)重要問題則是數(shù)據(jù)權(quán)限的過濾,今天就來介紹一下實(shí)現(xiàn)的方案。
在之前的文章中曾經(jīng)介紹過通過自定義的三個(gè)注解 @RequiresLogin、 @RequiresPermissions 、 @RequiresRoles 實(shí)現(xiàn)微服務(wù)的鑒權(quán)其實(shí)就是參考Spring Security 內(nèi)置的注解實(shí)現(xiàn),有想要了解的請(qǐng)看:3 個(gè)注解,優(yōu)雅的實(shí)現(xiàn)微服務(wù)鑒權(quán)
在介紹數(shù)據(jù)權(quán)限之前,先來看下Spring Security 中內(nèi)置的8個(gè)權(quán)限注解,只有理解了這8個(gè)注解,對(duì)于理解碼猿慢病云管理系統(tǒng)中的實(shí)現(xiàn)方案就非常easy了。
Spring Security 內(nèi)置的權(quán)限注解是將鑒權(quán)下放到各個(gè)微服務(wù),想要了解在網(wǎng)關(guān)處統(tǒng)一鑒權(quán)處理的請(qǐng)看之前分享的文章:實(shí)戰(zhàn)干貨!Spring Cloud Gateway 整合 OAuth2.0 實(shí)現(xiàn)分布式統(tǒng)一認(rèn)證授權(quán)!
碼猿慢病云管理系統(tǒng)已在星球中持續(xù)更新,想要加入的私信!
Spring Security 中的權(quán)限注解
Spring Security 中支持多種數(shù)據(jù)權(quán)限注解,若想使用內(nèi)置的注解,首先需要通過@EnableGlobalMethodSecurity這個(gè)注解開啟權(quán)限注解的支持,代碼如下:
/**
* @author 公眾號(hào):碼猿技術(shù)專欄
* 自定義資源服務(wù)注解
* {@link com.code.ape.codeape.common.security.annotation.EnableCodeapeResourceServer}
*/
@Documented
@Inherited
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import({ CodeapeResourceServerAutoConfiguration.class, CodeapeResourceServerConfiguration.class })
public @interface EnableCodeapeResourceServer {}
在碼猿慢病云管理系統(tǒng)中是將Spring Security集成為一個(gè)Spring Boot Starter,因此需要一個(gè)直接開啟對(duì)于Spring Security的支持,EnableCodeapeResourceServer是自定義的資源服務(wù)注解,便于一鍵導(dǎo)入資源服務(wù)配置,只要是資源服務(wù),只需要在資源服務(wù)配置類上添加這個(gè)注解即可。
比如設(shè)備服務(wù)(codeape-device-biz)的啟動(dòng)類如下:

如果是直接集成Spring Security ,那么直接在配置類標(biāo)注@EnableGlobalMethodSecurity這個(gè)注解也是一樣效果,代碼如下:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
@EnableGlobalMethodSecurity注解的三個(gè)屬性如下:
prePostEnabled:設(shè)置為true,將會(huì)開啟 Spring Security 提供的四個(gè)權(quán)限注解,@PostAuthorize、@PostFilter、@PreAuthorize 以及 @PreFilter,這四個(gè)注解支持權(quán)限表達(dá)式,支持 SpEL,功能比較豐富。securedEnabled:設(shè)置為true,將會(huì)開啟 Spring Security 提供的 @Secured 注解,該注解不支持權(quán)限表達(dá)式。jsr250Enabled:設(shè)置為true,將會(huì)開啟 JSR-250 提供的注解,主要包括 @DenyAll、@PermitAll 以及 @RolesAllowed 三個(gè)注解,這些注解也不支持權(quán)限表達(dá)式。
以上的8個(gè)注解總結(jié)如下:
@PostAuthorize:在目標(biāo)方法執(zhí)行之后進(jìn)行權(quán)限校驗(yàn)。@PostFilter:在目標(biāo)方法執(zhí)行之后對(duì)方法的返回結(jié)果進(jìn)行過濾。@PreAuthorize:在目標(biāo)方法執(zhí)行之前進(jìn)行權(quán)限校驗(yàn)。@PreFilter:在目標(biāo)方法執(zhí)行之前對(duì)方法參數(shù)進(jìn)行過濾。@Secured:訪問目標(biāo)方法必須具備相應(yīng)的角色。@RolesAllowed:訪問目標(biāo)方法必須具備相應(yīng)的角色。
其實(shí)在日常開發(fā)中使用前四個(gè)注解已經(jīng)完全夠用,且支持靈活的SPEL權(quán)限表達(dá)式,方便定制。因此只需要設(shè)置prePostEnabled = true
權(quán)限注解使用
接下來就來簡單介紹一下這8個(gè)權(quán)限注解的使用。
1. @PreAuthorize
@PreAuthorize這個(gè)注解在方法執(zhí)行之前進(jìn)行安全校驗(yàn),支持SPEL,比如在接口使用代碼如下:
@RestController
@RequestMapping
public class HelloService {
@PreAuthorize("hasRole('IN_HOS_NURSE')")
@GetMapping
public String hello() {
return "hello";
}
}
@PreAuthorize("hasRole('IN_HOS_NURSE')")代碼含義則是只有擁有住院護(hù)士的角色的用戶才能訪問這個(gè)接口。這里用到了hasRole這個(gè)權(quán)限表達(dá)式,表示擁有某個(gè)角色
2. @PreFilter
@PreFilter這個(gè)注解主要是對(duì)參數(shù)進(jìn)行過濾,其中兩個(gè)屬性如下:
value :SPEL表達(dá)式校驗(yàn)filterTarget:多個(gè)參數(shù)的情況下,指定對(duì)某個(gè)參數(shù)校驗(yàn)
使用如下:
@RestController
@RequestMapping
public class HelloService {
@PreFilter(value = "obj.id!=1",filterTarget = "users")
@GetMapping
public String hello(List<Obj> obj,Integer a) {
return "hello";
}
}
3. @PostAuthorize
@PostAuthorize是在方法執(zhí)行之后進(jìn)行數(shù)據(jù)校驗(yàn),平常所有的數(shù)據(jù)校驗(yàn)一般是在方法執(zhí)行之前,所以一般結(jié)合@PreAuthorize使用。
PostAuthorize中內(nèi)置了一個(gè)returnObject返回值,對(duì)方法的返回值校驗(yàn),使用如下:
@RestController
@RequestMapping
public class HelloService {
@PostAuthorize(value = "returnObject.id==1")
@GetMapping
public Obj hello(List<Obj> obj,Integer a) {
return "hello";
}
}
這個(gè)接口的返回值的id必須等于1才會(huì)通過,否則將會(huì)拋出異常。
4. @PostFilter
@PostFilter 注解是在目標(biāo)方法執(zhí)行之后,對(duì)目標(biāo)方法的返回結(jié)果進(jìn)行過濾,該注解中包含了一個(gè)內(nèi)置對(duì)象 filterObject,表示目標(biāo)方法返回的集合/數(shù)組中的具體元素:
@RestController
@RequestMapping
public class HelloService {
@PostFilter(value = "filterObject.id==1")
@GetMapping
public Obj hello(List<Obj> obj,Integer a) {
return "hello";
}
}
5. @Secured
@Secured 注解也是 Spring Security 提供的權(quán)限注解,不同于前面四個(gè)注解,該注解不支持權(quán)限表達(dá)式,只能做一些簡單的權(quán)限描述。
使用如下:
@RestController
@RequestMapping
public class HelloService {
@Secured({"ROLE_IN_HOS_NURSE","ROLE_IN_HOS_DOC"})
@GetMapping
public Obj hello(List<Obj> obj,Integer a) {
return "hello";
}
}
這段代碼表示只有當(dāng)前用戶擁有住院護(hù)士、住院醫(yī)生的權(quán)限才能訪問這個(gè)接口。
@Secured能夠做的,@PreAuthorize也都能做,且給的更多!
6. @DenyAll
@DenyAll 是 JSR-250 提供的方法注解,顧名思義,拒絕所有請(qǐng)求。
@RestController
@RequestMapping
public class HelloService {
@DenyAll
@GetMapping
public String hello() {
return "hello";
}
}
7. @PermitAll
@PermitAll 也是 JSR-250 提供的方法注解,顧名思義,允許所有訪問!
@RestController
@RequestMapping
public class HelloService {
@PermitAll
@GetMapping
public String hello() {
return "hello";
}
}
8. @RolesAllowed
@RolesAllowed 也是 JSR-250 提供的注解,可以添加在方法上或者類上,當(dāng)添加在類上時(shí),表示該注解對(duì)類中的所有方法生效;如果類上和方法上都有該注解,并且起沖突,則以方法上的注解為準(zhǔn)。
@RestController
@RequestMapping
public class HelloService {
@RolesAllowed({"IN_HOS_NURSE","IN_HOS_DOC"})
@GetMapping
public Obj hello(List<Obj> obj,Integer a) {
return "hello";
}
}
這段代碼表示只有當(dāng)前用戶擁有住院護(hù)士、住院醫(yī)生的權(quán)限才能訪問這個(gè)接口。
根據(jù)上述的介紹,大致理解了這8個(gè)注解,實(shí)際項(xiàng)目中建議使用@PostAuthorize、@PostFilter、@PreAuthorize 以及 @PreFilter這四個(gè)注解,完全夠用了!
慢病云管理系統(tǒng)的實(shí)踐
在碼猿慢病云管理系統(tǒng)中使用的權(quán)限注解是@PreAuthorize,在接口執(zhí)行之前對(duì)數(shù)據(jù)權(quán)限進(jìn)行校驗(yàn)。
比如住院服務(wù)codeape-inhos-biz中的分頁查詢住院患者接口如下:

這里的@PreAuthorize("@pms.hasPermission('inhos_patinfohot_get')" )則是對(duì)用戶的權(quán)限進(jìn)行攔截校驗(yàn),只有擁有inhos_patinfohot_get權(quán)限的用戶才能訪問這個(gè)接口。
而這里是直接通過SPEL表達(dá)式調(diào)用IOC容器中的方法進(jìn)行攔截校驗(yàn),代碼如下:
com.code.ape.codeape.common.security.component.PermissionService#hasPermission

邏輯很簡單,從SecurityContext中獲取用戶的權(quán)限和指定的權(quán)限進(jìn)行比較,校驗(yàn)通過則返回true。
總結(jié)
本篇文章介紹了Spring Security 中內(nèi)置的8個(gè)權(quán)限注解以及碼猿慢病云管理系統(tǒng)中的實(shí)踐,這個(gè)權(quán)限注解的使用是必須將權(quán)限下放到微服務(wù)鑒權(quán)才能用到,如果你的系統(tǒng)是在網(wǎng)關(guān)處統(tǒng)一鑒權(quán)則用不到。