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


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.