사용자 권한으로 메뉴 항목 저장


11

PHP와 MySQL에서 메뉴 시스템을 만들고 있습니다. 몇 가지 다른 메뉴가 있으며 각 메뉴에는 연결된 메뉴 항목이 있습니다.

사이트에서 사용자 권한이 다르므로 일부 사용자는 모든 메뉴 항목을 볼 수 있으며 일부 항목은 일부 사용자에게 숨겨져 있습니다. 앞으로 더 많은 유형의 사용자를 쉽게 추가 할 수있는 깔끔한 방식으로 권한을 처리 할 수있는 방법이 궁금합니다.

지금까지 내가 가진 것은 다음과 같습니다.

-------------------
|Menus
-------------------
|id| |display name|
-------------------

----------------------------------------------------------
|Menu items
----------------------------------------------------------
|id| |menu_id| |label| |link| |parent| |sort| |permission|
----------------------------------------------------------

permission열이 현재 사용자의 권한 ID와 일치 할 수있는 쉼표로 구분 된 문자열 일 수 있다고 생각합니다 . 또한 현재 존재하는 권한의 모든 가능한 조합을 정의하는 다른 테이블에 대한 참조 일 수도 있습니다.

한 가지 해결책은 권한이 유일한 차이점 인 여러 메뉴 항목을 단순히 저장하는 것인데, 이는 중복 스토리지 및 관리가 어려울 수 있습니다.

나는 이것을 어떻게 구성하고 깨끗하고 역동적이며 엉뚱한 것으로 간주 될 수 있는지에 대한 생각을 듣고 싶습니다.

감사.


사용자에게 공통점이 있습니까? 일반적으로 메뉴 항목을 기능 그룹으로 그룹화하고 해당 그룹에 사용자를 지정합니다 (예 : 관리자, DB 사용자, 트레이더 등). 그런 다음 기술 선택에 따라 그룹을 관리하기 만하면됩니다. 이것은 Active Directory와 같은 것을 사용하여 관리 할 수 ​​있습니다.
Michael

1
여기에 많은 좋은 답변이 있지만 ACL에 대해 읽으십시오. en.wikipedia.org/wiki/Access_control_list
Reactgular

답변:


18

ER 다이어그램을 사용하여 모델링합니다.

  • A는 PERMISSIONA를 부여 액세스입니다 ROLE주어진에 MENU_ITEM.
  • ROLE은 이름이 지정된 사전 정의 된 권한 세트입니다.
  • A USER에는 많은 ROLE이 부여 될 수 있습니다.
  • 사용자 대신 역할에 권한을 할당하면 권한을 훨씬 쉽게 관리 할 수 ​​있습니다.

여기에 이미지 설명을 입력하십시오

그런 다음 매번 조인을 작성할 필요가 없도록 뷰를 만들 수 있습니다.

create or replace view v_user_permissions
select
    distinct mi.id, mi.menu_id. mi.label. mi.link, mi.parent, mi.sort, u.user_id
from
    user u
    join user_role ur on (u.user_id = ur.user_id)
    join role ro on (ur.role_id = role.role_id)
    join permission per on (ro.role_id = per.role_id)
    join menu_item mi on (per.metu_item_id = mi.metu_item_id)

그런 다음 사용자가 액세스 할 수있는 메뉴 항목을 알고 싶을 때마다 쿼리 할 수 ​​있습니다.

select * from v_user_permissions up where up.user_id = 12736 order by up.sort

편집하다:

사용자에게 여러 역할이 부여 될 수 있으므로 역할의 권한이 겹칠 수 있습니다. 즉, 두 개의 다른 역할이 동일한 메뉴 항목에 액세스 할 수 있습니다. 역할을 정의 할 때 다른 역할과 공통된 권한이 있는지 여부를 미리 알 수 없습니다. 그러나 집합 집합에 관한 것이기 때문에 주어진 권한이 집합의 일부인지 아닌지 중요합니다. 따라서 distinct뷰 의 절.


정말 고마워 내가 왜 그것을 스스로 그릴 수 없었는지 알 수 없습니다. 내가 막혔고 경험이없는 것 같아요 :)
span

Ack, 나는 이해했지만 분명히 이해하지 못했다고 생각했다. 단일 메뉴 항목에 대해 여러 권한을 갖는 방법은 무엇입니까?
span

1
@span 사용자는 여러 역할을 부여받을 수 있고 역할 권한이 겹칠 수 있으므로 두 개의 다른 역할이 동일한 메뉴 항목에 액세스 할 수 있습니다. 역할을 정의 할 때 역할에 공통된 권한이있는 다른 역할과 함께 역할이 부여되는지 미리 알 수 없습니다. 그러나이 문제는 집합의 결합에 관한 것이기 때문에 주어진 권한이 집합의 일부인지 아닌지 만 중요합니다.
Tulains Córdova

감사합니다. 답을 얻을 때까지 답을 계속 읽겠습니다.). 내 실수는 메뉴 항목을 분리하는 역할과 함께 단일 권한을 사용할 수 있다고 생각한 것입니다. 메뉴 항목의 각 '유형'에 대한 권한이 필요한 것 같습니다. 다시 한 번 도와 주셔서 감사합니다! 벤 다이어그램을 그리고 머리 주위를 제대로 둘러 볼 수 있는지 알아 봅니다 \ o /
span

5

쉼표로 구분 된 목록이 있다는 것은 메뉴에 대해 쿼리를 수행 할 때마다 하위 문자열 비교를 수행한다는 의미입니다. 이것은 이상적이지 않습니다.

테이블을 정규화해야합니다.

---------------------------------------------
|Menu items
---------------------------------------------
|id| |menu_id| |label| |link| |parent| |sort|
---------------------------------------------

+---------------------------+
| menu_permission           |
|---------------------------|
| |menu_permission_id| (pk) |
| |menu_id| (fk)            |
| |permission|              |
+---------------------------+

당신은 여전히 (어떤 이유로) 쉼표로 구분 된 목록을 원한다면, 당신은 다음과 같은 것들로 그것을 해낼 수 group_concat있는 MySQL의 wm_concat 에서 오라클 다른 언어 또는 유사한 기능을한다.

이것의 장점은 여러 가지입니다.

첫째, 전화의 실용성이 있습니다. 임의로 큰 문자열에 대해 하위 문자열을 수행하면 (크기를 수정하면 나중에 문자열을 채울 때 문제가 발생하여 a대신 대신 권한을 얻기 시작 another_permission함) 각 행에서 문자열을 스캔하는 것을 의미합니다. 이것은 데이터베이스가 최적화 된 것이 아닙니다.

둘째, 작성하는 쿼리가 훨씬 간단 해집니다. 권한 'foo'가 쉼표로 구분 된 목록에 있는지 확인하려면 'foo'를 확인해야합니다.

... permission like "%foo%" ...

그러나 권한이 'foobar'인 경우에는 위양성을 나타냅니다. 따라서 이제 다음과 같은 테스트가 필요합니다.

... permission like "%,foo,%" ...

그러나 'foo'가 문자열의 시작 또는 끝에 있으면 거짓 부정을 줄 것입니다. 그것은 다음과 같은 것으로 이어집니다

... (permission like "foo,%" 
  or permission like "%,foo,%" 
  or permission like "%,foo" ) ...

문자열을 여러 번 스캔해야 할 수도 있습니다. 이 방법은 광기로 이어집니다.

이 모든 것에는 매개 변수 바인딩을 수행 할 수있는 실용적인 기능이 없습니다 (아직도 더 못생긴 것입니다).

필드를 정규화하면 데이터베이스의 유연성과 가독성이 훨씬 향상됩니다. 후회하지 않을 것입니다.


큰 답변을 주셔서 감사합니다. 더 많은 지식을 얻었으며 user61852 솔루션이 현재 가장 적합하다고 생각합니다.
span

3

이에 대한 고전적인 접근 방식은 User -> UserGroup다음과 같습니다 Menu -> MenuItem -> UserGroup. 정수 값을 사용하여 권한 수준을 측정합니다.

-------------------
|Menu
-------------------
|id| |display name|
-------------------

-------------------------------------------------------------
|Menu Item
-------------------------------------------------------------
|id| |menu_id| |label| |link| |parent| |sort| | min_option1
-------------------------------------------------------------

-------------------------------------------
| User
-------------------------------------------
|id| | username | password | user_group_id
-------------------------------------------

-------------------------------------------
| User Group
-------------------------------------------
|id| option1 | option2 | option2
-------------------------------------------

현재 사용자의 메뉴를 표시해야 할 경우 이와 같은 데이터베이스를 쿼리 할 수 ​​있습니다.

SELECT * FROM `MenuItem`
    LEFT JOIN `UserGroup` ON (`MenuItem`.`user_group_id` = `UserGroup`.`id`)
    LEFT JOIN `User` ON (`UserGroup`.`id` = `User`.`user_group_id` AND `User`.`id` = $current_user_id)
        WHERE `MenuItem`.`menu_id` = $menu_id AND `UserGroup`.`option1` >= `MenuItem`.`min_option1`;

조건에 따라 현재 사용자에게 표시되는 메뉴 만 선택합니다 option1.

또는 현재 세션에 현재 사용자의 그룹 세부 정보를 저장하면 조인이 필요하지 않습니다.

SELECT * FROM `MenuItem` WHERE `MenuItem`.`menu_id` = $menu_id AND `MenuItem`.`min_option1` >= $user_group_option1;

메뉴 항목 당 여러 권한을 저장하려는 경우 사용자 역할과 비즈니스 논리를 혼동하지 않도록주의해야합니다.


2
이 디자인은 각 MenuItem을 하나의 UserGroup에 묶을 수 있도록합니다. 즉, 제한된 메뉴 또는 데이터 복제입니다. 실제로는 이상적으로 연결 테이블을 원합니다. 또한 복수형으로 DB 테이블 명명을 선택하면 슬프게됩니다.)
Ed James

@ EdWoodcock 오 아주 좋은 지적. 권한 수준 (int)으로 이동 한 다음 사용자의 그룹 수준과 비교해야합니다. 변경하겠습니다. 내가 CakePHP를 사용함으로써 야기 된 복수의 이름 습관에 주목하라. 이상한 점은 프레임 워크가 쿼리의 테이블에 단일 별칭을 사용하기 때문입니다.
Reactgular

@MatthewFoscarini 걱정하지 마십시오. 코드베이스가 일관된 한 실제로 걱정하지 않습니다.)
Ed James

1
멋진 답변입니다. 다음에 이것을 할 때 이것을 염두에 두겠습니다. 지금은 user61852 솔루션이 기존 코드를 많이 변경할 필요가 없기 때문에 가장 적합하다고 생각합니다. 감사!
span
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.