大家好,,我是不才陳某~
在碼猿慢病云管理系統(tǒng)采用的是Spring Cloud 集成Spring Security OAuth2的方式實(shí)現(xiàn)認(rèn)證,、鑒權(quán),其中涉及到的一個(gè)重要問(wèn)題則是數(shù)據(jù)權(quán)限的過(guò)濾,,今天就來(lái)介紹一下實(shí)現(xiàn)的方案,。
在之前的文章中曾經(jīng)介紹過(guò)通過(guò)自定義的三個(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)限之前,,先來(lái)看下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)置的注解,,首先需要通過(guò)@EnableGlobalMethodSecurity
這個(gè)注解開(kāi)啟權(quán)限注解的支持,代碼如下:
/**
* @author 公眾號(hào):碼猿技術(shù)專(zhuān)欄
* 自定義資源服務(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è)直接開(kāi)啟對(duì)于Spring Security的支持,,EnableCodeapeResourceServer
是自定義的資源服務(wù)注解,便于一鍵導(dǎo)入資源服務(wù)配置,只要是資源服務(wù),,只需要在資源服務(wù)配置類(lèi)上添加這個(gè)注解即可,。
比如設(shè)備服務(wù)(codeape-device-biz)的啟動(dòng)類(lèi)如下:
如果是直接集成Spring Security ,那么直接在配置類(lèi)標(biāo)注@EnableGlobalMethodSecurity
這個(gè)注解也是一樣效果,,代碼如下:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
@EnableGlobalMethodSecurity
注解的三個(gè)屬性如下:
prePostEnabled
:設(shè)置為true,,將會(huì)開(kāi)啟 Spring Security
提供的四個(gè)權(quán)限注解,@PostAuthorize
,、@PostFilter
,、@PreAuthorize
以及 @PreFilter
,這四個(gè)注解支持權(quán)限表達(dá)式,,支持 SpEL,,功能比較豐富。securedEnabled
:設(shè)置為true,,將會(huì)開(kāi)啟 Spring Security
提供的 @Secured
注解,,該注解不支持權(quán)限表達(dá)式。jsr250Enabled
:設(shè)置為true,,將會(huì)開(kāi)啟 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)行過(guò)濾,。@PreAuthorize
:在目標(biāo)方法執(zhí)行之前進(jìn)行權(quán)限校驗(yàn),。@PreFilter
:在目標(biāo)方法執(zhí)行之前對(duì)方法參數(shù)進(jìn)行過(guò)濾。@Secured
:訪(fǎng)問(wèn)目標(biāo)方法必須具備相應(yīng)的角色,。@DenyAll
:拒絕所有訪(fǎng)問(wèn),。@PermitAll
:允許所有訪(fǎng)問(wèn)。@RolesAllowed
:訪(fǎng)問(wèn)目標(biāo)方法必須具備相應(yīng)的角色,。
其實(shí)在日常開(kāi)發(fā)中使用前四個(gè)注解已經(jīng)完全夠用,,且支持靈活的SPEL權(quán)限表達(dá)式,方便定制,。因此只需要設(shè)置prePostEnabled = true
權(quán)限注解使用
接下來(lái)就來(lái)簡(jiǎ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ù)士的角色的用戶(hù)才能訪(fǎng)問(wèn)這個(gè)接口,。這里用到了hasRole
這個(gè)權(quán)限表達(dá)式,表示擁有某個(gè)角色
2. @PreFilter
@PreFilter
這個(gè)注解主要是對(duì)參數(shù)進(jìn)行過(guò)濾,,其中兩個(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ì)通過(guò),,否則將會(huì)拋出異常,。
4. @PostFilter
@PostFilter
注解是在目標(biāo)方法執(zhí)行之后,對(duì)目標(biāo)方法的返回結(jié)果進(jìn)行過(guò)濾,,該注解中包含了一個(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á)式,只能做一些簡(jiǎn)單的權(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ù)擁有住院護(hù)士,、住院醫(yī)生的權(quán)限才能訪(fǎng)問(wè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
提供的方法注解,,顧名思義,,允許所有訪(fǎng)問(wèn)!
@RestController
@RequestMapping
public class HelloService {
@PermitAll
@GetMapping
public String hello() {
return "hello";
}
}
8. @RolesAllowed
@RolesAllowed
也是 JSR-250 提供的注解,,可以添加在方法上或者類(lèi)上,,當(dāng)添加在類(lèi)上時(shí),表示該注解對(duì)類(lèi)中的所有方法生效,;如果類(lèi)上和方法上都有該注解,,并且起沖突,則以方法上的注解為準(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ù)擁有住院護(hù)士,、住院醫(yī)生的權(quán)限才能訪(fǎng)問(wè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
中的分頁(yè)查詢(xún)住院患者接口如下:
這里的@PreAuthorize("@pms.hasPermission('inhos_patinfohot_get')" )
則是對(duì)用戶(hù)的權(quán)限進(jìn)行攔截校驗(yàn),,只有擁有inhos_patinfohot_get
權(quán)限的用戶(hù)才能訪(fǎng)問(wèn)這個(gè)接口。
而這里是直接通過(guò)SPEL表達(dá)式調(diào)用IOC容器中的方法進(jìn)行攔截校驗(yàn),,代碼如下:
com.code.ape.codeape.common.security.component.PermissionService#hasPermission
邏輯很簡(jiǎn)單,,從SecurityContext中獲取用戶(hù)的權(quán)限和指定的權(quán)限進(jìn)行比較,校驗(yàn)通過(guò)則返回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)則用不到,。