自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

醫(yī)療系統(tǒng)的權限就該這樣設計,穩(wěn)!

開發(fā) 架構
這節(jié)內容介紹了RBAC權限模型以及碼猿慢病云管理系統(tǒng)中權限是如何設計的,最重要的是科室/病區(qū)權限的設計,大家一定要理解其中的邏輯,幾乎所有的醫(yī)療系統(tǒng)都是按照這個邏輯處理的。

權限管控可以通俗的理解為權力限制,即不同的人由于擁有不同權力,他所看到的、能使用的可能不一樣。對應到一個應用系統(tǒng),其實就是一個用戶可能擁有不同的數(shù)據權限(看到的)和操作權限(使用的)。

主流的權限模型主要分為以下五種:

  • ACL模型:訪問控制列表
  • DAC模型:自主訪問控制
  • MAC模型:強制訪問控制
  • ABAC模型:基于屬性的訪問控制
  • RBAC模型:基于角色的權限訪問控制

目前主流的權限模型是RBAC模型,碼猿慢病云管理系統(tǒng)則是使用RBAC模型進行權限控制。

關于以上5種權限模型在之前一篇文章中詳細介紹過:權限系統(tǒng)就該這么設計,yyds

RBAC 基于角色的權限訪問控制

Role-Based Access Control,核心在于用戶只和角色關聯(lián),而角色代表對了權限,是一系列權限的集合。

RBAC三要素:

  1. 用戶:系統(tǒng)中所有的賬戶
  2. 角色:一系列權限的集合(如:管理員,開發(fā)者,審計管理員等)
  3. 權限:菜單,按鈕,數(shù)據的增刪改查等詳細權限。

在RBAC中,權限與角色相關聯(lián),用戶通過成為適當角色的成員而得到這些角色的權限。

角色是為了完成各種工作而創(chuàng)造,用戶則依據它的責任和資格來被指派相應的角色,用戶可以很容易地從一個角色被指派到另一個角色。

角色可依新的需求和系統(tǒng)的合并而賦予新的權限,而權限也可根據需要而從某角色中回收。角色與角色的關系同樣也存在繼承關系防止越權。

優(yōu)點:便于角色劃分,更靈活的授權管理;最小顆粒度授權;

在碼猿慢病云管理系統(tǒng)(醫(yī)療系統(tǒng))的用戶、角色、權限代表什么呢?

1. 用戶

這里的用戶和其他系統(tǒng)并無區(qū)別,則是能登錄系統(tǒng)的用戶,對應的表為:codepae/sys_user,字段屬性如下:

字段

類型

注釋

user_id

bigint

用戶唯一ID

name

varchar

姓名

gender

char

性別,字典

username

varchar

用戶名/賬號

password

varchar

密碼

dept_id

bigint

科室ID

hos_id

bigint

醫(yī)院ID

salt

varchar

隨機鹽

phone

varchar

手機號

avatar

varchar

頭像

lock_flag

char

0-正常,9-鎖定

del_flag

char

0-正常,1-刪除

其中比較重要的字段:

  1. username:用戶登錄系統(tǒng)的賬號,醫(yī)療系統(tǒng)中則是HIS系統(tǒng)中的工號,(username,hos_id,del_flag)組成唯一索引,同一家醫(yī)院這個賬號必須是唯一
  2. hos_id:醫(yī)院的ID,多租戶架構模式下區(qū)分租戶的字段
  3. dept_id:科室ID/病區(qū)ID,醫(yī)院中的醫(yī)生、護士是按照科室/病區(qū)管理患者的,因此在入職時就會分配到對應的科室/病區(qū),比如女人的婦科病,去醫(yī)院看病掛的肯定是婦科,這個婦科門診則是有對應的醫(yī)生坐診,不可能找個骨科的醫(yī)生去看婦科的毛病

為什么要有科室、病區(qū)這兩個概念?

科室則是平常我們醫(yī)院掛號經??吹降目剖遥热鐙D科、骨科、內分泌科、心內科、心腦血管科等

病區(qū)這個概念是針對住院來說,住過院的應該都知道護士照顧病人是通過病區(qū)->病房->床位號定位病人,比如二十病區(qū)->302房間->10號床

醫(yī)院為了病房能夠更好的管理,節(jié)省醫(yī)護的資源,一個病區(qū)中包含多個科室的患者,比如新生兒科、產科、兒科這三個科室你會看到里面的住院患者都是住在同一個病區(qū),同一批護士管理,比如十病區(qū)。

這樣應該就能理解了,大部分的HIS系統(tǒng)中,醫(yī)生是劃分到科室管理,比如婦科,骨科,畢竟術業(yè)有專攻,護士是按照病區(qū)劃分管理,因為護士本質上是照顧病人,打打針等一些工作,專一性不是那么高;因此在sys_user用戶表中的dept_id既能表示科室也能表示病區(qū)了。

PS:一些比較落后的小醫(yī)院,HIS系統(tǒng)比較老舊,醫(yī)生、護士還是按照科室管理

2. 角色

在醫(yī)院中的主要角色則是:醫(yī)生和護士,這個想必大家都能理解

碼猿慢病云管理系統(tǒng)中內置了七個角色,已經完全夠用了,如下:

圖片圖片

  • 管理員:這個是每個醫(yī)院的系統(tǒng)管理員,在添加醫(yī)院的時候會指定一個管理員
  • 系統(tǒng)管理員:這個是整個系統(tǒng)的管理員,擁有最高權限,可以看到所有醫(yī)院的數(shù)據
  • 醫(yī)生:醫(yī)生的角色
  • 護士:護士的角色

對應數(shù)據庫:codeape/sys_role,如下:

字段

類型

注釋

role_id

bigint

唯一Id

role_name

varchar

角色名稱

role_code

varchar

角色代碼

role_desc

varchar

角色描述

del_flag

char

刪除標識:0-正常,1-刪除

和用戶通過另外一張表存儲關聯(lián)關系:codeape/sys_user_role

字段

類型

注釋

user_id

bigint

用戶唯一ID

role_id

bigint

角色唯一ID

碼猿慢病云管理系統(tǒng)中醫(yī)生和護士這兩個角色的最大區(qū)別:護士需要手持PDA(數(shù)據采集設備)采集數(shù)據(血糖、尿酸、血酮),添加數(shù)據等操作,醫(yī)生則是每天查看患者的數(shù)據為治療提供輔助

3. 權限

碼猿慢病云管理系統(tǒng)中的權限有如下三類:

  1. 菜單的權限:客戶端菜單的權限
  2. 按鈕/接口的權限:客戶端按鈕/接口的權限,比如添加患者這個
  3. 科室/病區(qū)的權限:

1. 菜單的權限

控制客戶端的菜單顯示,如下:

圖片圖片

目前有這幾個根菜單+子菜單。

2. 按鈕權限

客戶端按鈕的權限,比如新增、刪除、編輯按鈕的權限,比如住院患者的4個按鈕,如下:

圖片圖片

每個按鈕都有一個權限標識編碼,比如inhos_patinfohot_get,客戶端只需要判斷當前登錄用戶的權限樹中是否存在這個權限,有則顯示,沒有則不顯示

3. 接口權限

客戶端的接口權限和按鈕權限共用,比如查詢住院患者這個權限對應的標識也是:inhos_patinfohot_get

那么這個接口權限如何控制?碼猿慢病云管理系統(tǒng)中是將接口權限的鑒權下沉到各個微服務,交給開發(fā)者在開發(fā)接口時通過@PreAuthorize注解控制權限,比如查詢住院患者列表的這個接口,如下:

//com.code.ape.codeape.inhos.controller.PatInfoHotController#getPatInfoHotPage
 @Operation(summary = "分頁查詢在院患者", description = "分頁查詢在院患者")
    @GetMapping("/page" )
 @InjectAuth
    @PreAuthorize("@pms.hasPermission('inhos_patinfohot_get')" )
    public R<Page<PatInfoVO>> getPatInfoHotPage(Page<PatInfoVO> page, PatInfoDTO dto) {
        return R.ok(patInfoHotService.listPage(page,dto));
    }

@PreAuthorize這個注解是Spring Security內置的鑒權接口,其中的value這個屬性支持SPEL表達式,真實的實現(xiàn)代碼如下:

/**
 * @author 公眾號:碼猿技術專欄   版權:不才陳某所署,侵權必究
 * {@link com.code.ape.codeape.common.security.component.PermissionService}
 */
public class PermissionService {
 /**
  * 判斷接口是否有任意xxx,xxx權限
  * @param permissions 權限
  * @return {boolean}
  */
 public boolean hasPermission(String... permissions) {
  if (ArrayUtil.isEmpty(permissions)) {
   return false;
  }
        //代碼(1)
  Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  if (authentication == null) {
   return false;
  }
        //代碼(2)
  Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
  ////代碼(3)
        return authorities.stream()
   .map(GrantedAuthority::getAuthority)
   .filter(StringUtils::hasText)
   .anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x));
 }
}

邏輯其實很簡單,上述代碼三個部分:

  • 代碼(1) :從Spring Security 上下文中獲取當前用戶登錄的身份信息Authentication,其中就包括權限
  • 代碼(2) :從用戶身份信息Authentication中獲取用戶的權限樹
  • 代碼(3) :將當前登錄用戶的權限和@PreAuthorize傳入的權限比較,判斷是否鑒權通過

4. 科室/病區(qū)權限

這個權限則是比較特殊了,先描述一下場景:

在醫(yī)療系統(tǒng)中,醫(yī)生/護士是無權限查看全部科室的數(shù)據的,只能查看自己負責科室/病區(qū)的數(shù)據,這樣是為了避免醫(yī)療事故;你想想如果有個心懷不軌的醫(yī)生,隨意更改其他科室/病區(qū)患者的數(shù)據,導致醫(yī)生誤判病情,這樣的責任誰來承擔?

所以醫(yī)療系統(tǒng)中都需要控制醫(yī)護科室/病區(qū)這個權限,這樣才能保證不發(fā)生不必要的醫(yī)療事故。

碼猿慢病云管理系統(tǒng)中的科室/病區(qū)權限如何控制的呢?

在新增醫(yī)護的時候有個科室權限的多選器,如下圖:

圖片圖片

這樣就能輕松設置醫(yī)護的科室/病區(qū)權限了,這部分對應關系是持久化在codeape/sys_user_dept這張表中,如下:

字段

類型

注釋

user_id

bigint

用戶ID

dept_id

bigint

科室/病區(qū)ID

del_flag

varchar

刪除標志

那么此時當前醫(yī)護的科室/病區(qū)權限如何計算呢?

先給答案,分為兩種情況;

第一種:WEB端/PAD端

先說第一種:在WEB端/PAD端,醫(yī)護的權限=醫(yī)護所在的科室+醫(yī)護的科室權限+關聯(lián)科室

什么意思?比如白鹿這個護士,如下圖:

圖片圖片

所屬科室為內分泌科,科室權限為神經內科+內分泌科+心內科,那么前面兩層的權限則是神經內科+內分泌科+心內科(注意去重)

那么關聯(lián)科室什么意思?比如神經內科下面有個神經內科病區(qū),但是醫(yī)護的科室在入職時都設置在了神經內科,那么他們如何能看到神經內科病區(qū)的數(shù)據呢?

一種方案可以在科室權限那一欄再加上神經內科病區(qū),這種當然可行,但是你要為每個醫(yī)護都設置一遍。

第二種方案:可以將神經內科和神經內科病區(qū)關聯(lián)起來,這樣只要有神經內科這個權限,那么就必然有神經內科病區(qū)這個權限,這個在碼猿慢病云管理系統(tǒng)中也有設置關聯(lián)關系,如下圖:

圖片圖片

在添加科室的時候可以選擇根節(jié)點科室。

對應的關系持久化在codeape/sys_dept_relation中,結構如下:

字段

類型

注釋

ancestor


bigint

祖先節(jié)點(科室/病區(qū)ID)

descendant

bigint

子節(jié)點(科室/病區(qū)ID)

科室/病區(qū)權限在用戶登錄時就會查詢出來放到SecurityContext上下文中,具體的方法如下圖:

圖片圖片

那在醫(yī)護查詢數(shù)據如何去根據這個科室/病區(qū)權限過濾呢?

在請求DTO中有個基礎實體類com.code.ape.codeape.common.core.entity.BaseParam,如下:

@Data
public class BaseParam {

   /**
    * 醫(yī)院Id
    */
   private Long hosId;

   /**
    * 用戶ID
    */
   private Long userId;

   /**
    * 醫(yī)護的科室權限
    */
   private List<Long> dataAuth;

   /**
    * 請求來源客戶端ID
    */
   private String clientId;

   /**
    * 設備的SN號
    */
   private String sn;
}

這個類中的所有屬性都會自動注入,只需要在controller方法中標注一個注解:@InjectAuth,如何做到的呢?

@InjectAuth這個注解是通過AOP方式自動注入參數(shù),代碼如下:

@Slf4j
@RequiredArgsConstructor
@Aspect
public class CodeapeInjectAuthAspect implements Ordered {


 @SneakyThrows
 @Around("@annotation(injectAuth) &&" +
   "(@annotation(org.springframework.web.bind.annotation.PostMapping)||" +
   "@annotation(org.springframework.web.bind.annotation.GetMapping)||" +
   "@annotation(org.springframework.web.bind.annotation.DeleteMapping)||" +
   "@annotation(org.springframework.web.bind.annotation.PutMapping)||" +
   "@annotation(org.springframework.web.bind.annotation.RequestMapping))")
 public Object around(ProceedingJoinPoint joinPoint, InjectAuth injectAuth) {
  if (injectAuth.enable()){
   CodeapeUser codeapeUser = Objects.requireNonNull(SecurityUtils.getUser());
   Object[] args = joinPoint.getArgs();
   for (int i = 0; i < args.length; i++) {
    if (!(args[i] instanceof BaseParam)) {
     continue;
    }
    BaseParam baseParam = (BaseParam) args[i];

    /**
     * 1. web端:權限就是當前登錄用戶的權限
     * 2. pda端,權限則是設備的權限+當前登錄用戶的權限
     * 這里的權限取值是token中的deptAuths,這個在登錄的時候就查詢出來,緩存在redis中,所以這里直接用就可以
     */
    //醫(yī)院管理員+系統(tǒng)管理員不賦予權限
    boolean flag= ArrayUtil.contains(codeapeUser.getRoleCodes(),SecurityConstants.SYSTEM_ADMIN_CODE)
  ||ArrayUtil.contains(codeapeUser.getRoleCodes(),SecurityConstants.HOS_ADMIN_CODE);
    baseParam.setDataAuth(flag?null:Arrays.asList(codeapeUser.getDeptAuths()));
    baseParam.setHosId(codeapeUser.getHosId());
    baseParam.setUserId(codeapeUser.getId());
    baseParam.setClientId(codeapeUser.getClientId());
    baseParam.setSn(codeapeUser.getSn());
   }
  }
  return joinPoint.proceed();
 }


 @Override
 public int getOrder() {
  return Ordered.HIGHEST_PRECEDENCE + 4;
 }
}

直接取的是CodeapeUser中的deptAuths,CodeapeUser則是SecurityContext上下文的用戶身份信息

這樣則能夠取到用戶的科室/病區(qū)權限,然后則能在SQL中根據這個dataAuth屬性去過濾數(shù)據了,比如分頁查詢住院患者的接口,controller方法如下:

com.code.ape.codeape.inhos.controller.PatInfoHotController#getPatInfoHotPage

圖片圖片

圖片圖片

SQL如下:

com.code.ape.codeape.inhos.mapper.PatInfoHotMapper#selectPatInfoPage

圖片圖片

這部分的SQL片段則是根據住院患者的科室去過濾。

第二種PDA端

這里的PDA指的是護士的手持設備,這個設備和智能手機一樣,根據自己賬號登錄上去,給大家大致畫一下PDA上都有哪些內容,如下圖:

圖片圖片

其實就和APP是一樣的,里面可以看到大致四塊內容(當然還有其他):

  1. 患者管理:這個是顯示所有的住院患者,護士可以選擇對應的患者進行數(shù)據采集,這樣采集的數(shù)據才能和患者自定綁定
  2. 檢測任務:這個則是醫(yī)生下的醫(yī)囑任務,按照時間段顯示,比如醫(yī)生下的三餐前后測血糖這個醫(yī)囑任務,則經過護士拆分后,則變成了6個子任務:空腹測血糖、早餐后測血糖、午餐前測血糖、午餐后測血糖、晚餐前測血糖、晚餐后測血糖。那么在每個時間段顯示要測血糖的患者床位即可,護士選擇對應的床位則可以測血糖
  3. 檢測記錄:這里是展示所有患者測量的血糖數(shù)據,按照時間段表格形式的展示
  4. 質控:這個則是設備的質控,護士每天要定時對設備進行質控(質量檢測),查看這臺設備測量是否準確

那么問題來了,PDA上需要顯示的數(shù)據是整個醫(yī)院的數(shù)據嗎?顯然不可能,也是需要根據護士科室/病區(qū)權限過濾,可以看到上方有一個科室的篩選項,默認是所有科室,則是當前登錄用戶的所有科室權限

那么PDA端的醫(yī)護權限和WEB端一樣嗎?

當然不是,因為設備存在以下兩種網絡情況:

  1. 在線:連上wifi或者SIM卡,這樣能夠時刻保持網絡暢通的情況下,屬于在線狀態(tài),拉數(shù)據/上傳數(shù)據直接訪問服務端即可
  2. 離線:有些醫(yī)院沒有內網的wifi或者SIM卡,只能連有線網絡,一旦設備拔掉網線去病房檢測,則是離線的狀態(tài)

離線情況下就需要設備本地做緩存了,那么這個緩存的數(shù)據到底拉哪些數(shù)據?不可能將整個醫(yī)院的數(shù)據都拉下來,設備的內存是有限的。這個時候就需要用到設備的權限了,在添加設備的時候有兩個的選項,如下:

圖片圖片

科室和關聯(lián)科室這兩個選項,一般一臺設備只供一個病區(qū)使用,此時將科室選項選擇對應的病區(qū)即可,那么特殊情況下,比如一病區(qū)和二病區(qū)共用一臺設備,此時就需要用到關聯(lián)科室了。

此時應該明白了設備的權限=科室+關聯(lián)科室

只要設備連上網絡,在用戶不登錄的情況下,調用接口獲取數(shù)據的時候就應該獲取的是設備權限的數(shù)據。

那登錄該臺設備的用戶權限呢?應該怎么取值呢?很簡單,分為兩種情況:

  1. 用戶的權限和設備的權限取并集
  2. 用戶的權限和設備的權限取交集

按照正常的邏輯是應該是第二種情況取交集,因為你護士沒有這個權限就不應該看到該科室/病區(qū)的數(shù)據,但是實際情況是很多醫(yī)院的護士都是輪轉的,比如這個月到一病區(qū),下個月到二病區(qū),他們的科室/病區(qū)權限的維護并不是很及時,主要是信息科的人員太懶了,這樣的話就會導致如果按照第二種情況取交集,那么這個護士登錄該臺設備就看不到自己所管的科室/病區(qū)的數(shù)據了。所以在碼猿慢病云管理系統(tǒng)中是采用的第一種方案。

相關代碼在com.code.ape.codeape.common.security.service.CodeapePDAUserDetailsServiceImpl#getUserDetails,如下圖:

圖片圖片

總結

這節(jié)內容介紹了RBAC權限模型以及碼猿慢病云管理系統(tǒng)中權限是如何設計的,最重要的是科室/病區(qū)權限的設計,大家一定要理解其中的邏輯,幾乎所有的醫(yī)療系統(tǒng)都是按照這個邏輯處理的。

本節(jié)內容摘錄了部分代碼,關于代碼的詳細介紹會在后面文章中介紹,現(xiàn)在先了解一下。

責任編輯:武曉燕 來源: 碼猿技術專欄
相關推薦

2022-07-18 08:39:18

ACL訪問控制機制

2025-04-15 02:25:00

2022-12-05 09:08:12

微服務灰度發(fā)布

2023-07-05 13:58:10

權限模型設計模式

2022-12-14 09:06:58

接口Spring解密

2024-09-09 00:02:00

2023-06-20 16:17:40

人工智能

2022-09-15 08:41:16

數(shù)據異構分庫分表

2022-12-13 15:17:35

2014-12-24 16:10:06

2018-01-02 09:36:55

程序員加薪年終

2015-05-11 17:38:38

華為敏捷網絡

2020-06-17 21:22:56

Serverless面試官架構

2016-01-29 16:06:04

華為視訊系統(tǒng)

2013-06-18 20:34:59

2017-07-24 10:53:06

東芝

2011-08-30 22:18:54

RADVISION遠程

2016-02-22 18:07:11

遠程醫(yī)療華為

2011-11-26 11:31:45

RADVISION遠程

2017-07-27 16:18:18

開源項目使用
點贊
收藏

51CTO技術棧公眾號