简体   繁体   English

存储用户帐户权限的最佳方法是什么?

[英]Best way to store permissions for the user account?

I have permission records that are tied to each account in my application. 我有与我的应用程序中的每个帐户绑定的权限记录。 Each account can have one or multiple permission records based on account type. 每个帐户可以根据帐户类型拥有一个或多个权限记录。 Here is example: 这是一个例子:

<cfquery name="qryUserPerm" datasource="#Application.dsn#">
    SELECT AccessType, AccessLevel, State, City, Building
    FROM Permissions
    WHERE AccountID = <cfqueryparam cfsqltype="cf_sql_integer" value="#trim(session.AccountID)#">
</cfquery>

Query above will produce data like this for one of the accounts: 上面的查询将为其中一个帐户生成如下数据:

RecID   AccountID   AccessType  AccessLevel State     City    Building
70      285A637D82B9    F            B        NY    New York    8010
71      285A637D82B9    F            B        NY    New York    5412
73      285A637D82B9    F            B        NY    New York    6103
74      285A637D82B9    F            B        NY    New York    3106

As you can see above this account have 4 records assigned to them. 如您所见,此帐户分配了4条记录。 Access Type can be Full F or View Only V . 访问类型可以是Full F或View Only V Access Level can be State 'S', City 'C' or Building 'B'. 访问级别可以是州'S',城市'C'或建筑'B'。 User can have only one access level assigned to them at the time, so for example there is no situation where user can have assigned City and State level. 用户当时只能为其分配一个访问级别,因此例如,用户无法分配城市和州级别。 My question is what would be the best way to organize the data from the query for specific access level? 我的问题是,从特定访问级别的查询中组织数据的最佳方法是什么? In this case I have to merge 4 records in list or array. 在这种情况下,我必须合并列表或数组中的4个记录。 State level only can have one permission record assigned, City and Building can have multiple records. 州级别只能分配一个权限记录,城市和建筑物可以有多个记录。 Here is example of what I have: 这是我的例子:

<cfset local.permissionType = "">
<cfset local.permissionLevel = "">
<cfset local.permissionList = "">

<cfloop query="qryUserPerm">
    <cfif qryUserPerm.AccessLevel EQ "S">
         <cfset local.permissionType = qryUserPerm.AccessType>
         <cfset local.permissionLevel = qryUserPerm.AccessLevel>
         <cfset local.permissionList = listAppend(permissionList, "", ",")>
    <cfelseif qryUserPerm.AccessLevel EQ "C">
         <cfset local.permissionType = qryUserPerm.AccessType>
         <cfset local.permissionLevel = qryUserPerm.AccessLevel>
         <cfset local.permissionList = listAppend(permissionList, qryUserPerm.City, ",")>
    <cfelseif qryUserPerm.AccessLevel EQ "B">
         <cfset local.permissionType = qryUserPerm.AccessType>
         <cfset local.permissionLevel = qryUserPerm.AccessLevel>
         <cfset local.permissionList = listAppend(permissionList, qryUserPerm.Building, ",")>
    <cfelse>
         <cfset local.permissionType = "">
         <cfset local.permissionLevel = "">
         <cfset local.permissionList = listAppend(permissionList, "", ",")>
    </cfif>
</cfloop>

It seems redundant to keep permissionType and permissionLevel inside of the loop but I do not know better way currently to avoid that. permissionTypepermissionLevel保留在循环内似乎是多余的,但我目前还不知道更好的方法来避免这种情况。 Also this makes process very dificult in case when I have to compare permission list. 这也使得在必须比较许可列表的情况下进程非常困难。 I would have to run this same process and build the list in order to compare that with Session.premissionList in case where currently logged user change their permissions. 我必须运行相同的进程并构建列表,以便在当前登录的用户更改其权限的情况下将其与Session.premissionList进行比较。 Is there any way to merge these records with SQL? 有没有办法将这些记录与SQL合并? Or this approach is better option? 或者这种方法是更好的选择?

This can be done in SQL itself, which may be more performant than manipulating the data in code. 这可以在SQL本身中完成,这可能比在代码中操作数据更高效。

One issue with the data is that the State , City and Building columns need to be unpivoted to then be turned into a comma-delimited list. 数据的一个问题是StateCityBuilding列需要不相关,然后才能转换为以逗号分隔的列表。

Since you are using SQL 2008, you have access to the functionality you need. 由于您使用的是SQL 2008,因此您可以访问所需的功能。

The query is: http://sqlfiddle.com/#!18/0f4f7/1 查询是: http//sqlfiddle.com/#!118 / ff4f7 / 1

; WITH cte AS (
  SELECT
      AccountID, AccessType, AccessLevel
      , CASE AccessLevel
          WHEN 'S' THEN State
          WHEN 'C' THEN City
          WHEN 'B' THEN Building
        END AS Permissions
  FROM Permissions
  WHERE AccountID = 
    <cfqueryparam cfsqltype="cf_sql_integer" value="#session.AccountID#"> 
    /* Dynamic variable here */
)
SELECT DISTINCT AccountID, AccessType, AccessLevel
  , CASE 
      WHEN AccessLevel = 'S' THEN Permissions 
      ELSE LEFT(ca.pl, COALESCE(LEN(ca.pl),0)-1)
    END AS PermissionList
FROM cte
CROSS APPLY (
  SELECT p.Permissions + ', '
  FROM cte p
  WHERE p.AccountID = cte.AccountID
    AND p.AccessType = cte.AccessType
    AND p.AccessLevel = cte.AccessLevel
  FOR XML PATH('')
) ca (pl)     ;

I start with a CTE to build out the "unpivoted" list of Permissions based on the AccessLevel . 我从CTE开始构建基于AccessLevel的“不透明” Permissions列表。 If this can be put in a SQL View, you can just leave out the WHERE statement here and just call it when you call the View. 如果这可以放在SQL视图中,您可以在此处省略WHERE语句,并在调用View时调用它。 A View would be my preference, if you can get it into your database. 如果您可以将视图放入数据库,那么View将是我的首选。

After I have the CTE, I just select the base columns ( AccountID , AccessType and AccessLevel , and then I CROSS APPLY a comma-delimited list of the Permissions . I use FOR XML PATH('') to build that comma-delimited list. 在我有CTE之后,我只选择基本列( AccountIDAccessTypeAccessLevel ,然后我CROSS APPLY以逗号分隔的Permissions列表。我使用FOR XML PATH('')来构建逗号分隔的列表。

If this is able to be converted to a View, it would be a simple 如果能够将其转换为View,那将很简单

<cfquery name="qryUserPerm" datasource="#Application.dsn#">
    SELECT AccessType, AccessLevel, PermissionList
    FROM myPermissionsView
    WHERE AccountID = <cfqueryparam cfsqltype="cf_sql_integer" value="#trim(session.AccountID)#">
</cfquery>

If not, you'll have to try running the above full query inside the cfquery tag. 如果没有,您将不得不尝试在cfquery标记内运行上面的完整查询。

This should give you back a dataset like: 这应该会给你一个数据集,如:

| AccessType | AccessLevel |         PermissionList |
|------------|-------------|------------------------|
|          F |           B | 8010, 5412, 6103, 3106 |

You only have one result to work with and won't have to loop. 您只能使用一个结果,而不必循环。

====================================================================== ================================================== ====================

If you want to go the in-code route, I'd still recommend trying to use cfscript to build out the structs. 如果你想进入代码内路由,我仍然建议你尝试使用cfscript来构建结构。 But, if you can have more than one AccessLevel, your results may not be what you think they should be. 但是,如果您可以拥有多个AccessLevel,那么您的结果可能不是您认为的那样。 You'll have to doublecheck your data. 您必须双重检查数据。

  local.permissionType = q2.AccessType ;
  local.permissionLevel = q2.AccessLevel ;

  switch( q2.AccessLevel ) {
    case "S" :  local.permissionList = q2.State ;
      break ;
    case "C" :  local.permissionList = ListRemoveDuplicates(ValueList(q2.City)) ;
      break ;
    case "B" :  local.permissionList = ListRemoveDuplicates(ValueList(q2.Building)) ;
      break ;
  }

https://trycf.com/gist/e811ec86f0d5a52fd9ce703f897cb5aa/acf2016?theme=monokai https://trycf.com/gist/e811ec86f0d5a52fd9ce703f897cb5aa/acf2016?theme=monokai

I would be tempted to remove the loop. 我很想去除循环。 I am thinking that this may make things a little simpler. 我想这可能会让事情变得更简单一些。

<cfset local.permissionType = "">
<cfset local.permissionLevel = "">
<cfset local.permissionList = "">


<cfif qryUserPerm.AccessLevel EQ "S">
     <cfset local.permissionType = qryUserPerm.AccessType>
     <cfset local.permissionLevel = qryUserPerm.AccessLevel>
     <cfset local.permissionList = qryUserPerm.State>
<cfelseif qryUserPerm.AccessLevel EQ "C">
     <cfset local.permissionType = qryUserPerm.AccessType>
     <cfset local.permissionLevel = qryUserPerm.AccessLevel>
     <cfset local.permissionList = ListRemoveDuplicates(ValueList(permissionList,qryUserPerm.City))>
<cfelseif qryUserPerm.AccessLevel EQ "B">
     <cfset local.permissionType = qryUserPerm.AccessType>
     <cfset local.permissionLevel = qryUserPerm.AccessLevel>
     <cfset local.permissionList = ListRemoveDuplicates(ValueList(permissionList,qryUserPerm.Building))>
</cfif>

And, if you want to compare the lists in future for equality, you may want to use: 并且,如果您希望将来比较列表中的相等性,您可能希望使用:

<cfset local.permissionList = ListSort(local.permissionList,"textnocase","asc")>

UPDATE: 更新:

<cfscript>

qryUserPerm = queryExecute("
  SELECT AccessType, AccessLevel, State, City, Building 
  FROM Permissions
  WHERE AccountID = :AccountID 
",
{
  AccountID = {value = Trim(session.AccountID), cfsqltype = "cf_sql_integer"}
},
{
  datasource = Application.dsn 
});

local.permissionType = "";
local.permissionLevel = "";
local.permissionList = "";

if(qryUserPerm.AccessLevel EQ "S"){
   local.permissionType = qryUserPerm.AccessType;
   local.permissionLevel = qryUserPerm.AccessLevel;
   local.permissionList = qryUserPerm.State;
}
else if(qryUserPerm.AccessLevel EQ "C"){
   local.permissionType = qryUserPerm.AccessType;
   local.permissionLevel = qryUserPerm.AccessLevel;
   local.permissionList = ListRemoveDuplicates(ValueList(permissionList,qryUserPerm.City));
}
else if(qryUserPerm.AccessLevel EQ "B"){
   local.permissionType = qryUserPerm.AccessType;
   local.permissionLevel = qryUserPerm.AccessLevel;
   local.permissionList = ListRemoveDuplicates(ValueList(permissionList,qryUserPerm.Building));
}

</cfscript>

You could trim down the code by using CASE to merge everything into a single column, based on the Access Level. 您可以使用CASE根据访问级别将所有内容合并到一个列中来减少代码。

SELECT AccessType
        , AccessLevel
        , CASE AccessLevel
            WHEN 'C' THEN City
            WHEN 'B' THEN Building
            WHEN 'S' THEN State
          END AS AccessValue
 FROM   Permissions
 WHERE  AccountID = <cfqueryparam cfsqltype="cf_sql_integer" value="#session.AccountID#">

Then build your list from that column. 然后从该列构建列表。 No cfif's needed. 不需要cfif。

 <cfset local.permissionType = qryUserPerm.AccessType>
 <cfset local.permissionLevel = qryUserPerm.AccessLevel>
 <cfset local.permissionList = valueList(qryUserPerm.AccessValue)>

You could also build the CSV list in SQL only , but not sure it's worth it in this scenario, since it's just as easy to build in CF. 您也可以仅在SQL中构建CSV列表 ,但在这种情况下不确定它是否值得,因为它在CF中构建起来同样容易。

SELECT TOP 1 AccessType
        , AccessLevel
        , STUFF(( SELECT ','+ l.AccessValue
                  FROM ( SELECT CASE AccessLevel 
                                  WHEN 'C' THEN City 
                                  WHEN 'B' THEN Building 
                                  WHEN 'S' THEN State 
                                END AS AccessValue
                         FROM   Permissions l
                         WHERE  l.AccountID = p.AccountID 
                     ) l
                  GROUP BY l.AccessValue
                  FOR XML PATH('')
                ),1,1,'') AS PermissionsList
 FROM   Permissions p            
 WHERE  AccountID = <cfqueryparam cfsqltype="cf_sql_integer" value="#session.AccountID#">       

Anyway, using the above the query will return everything you need in a single row: AccessType, AccessLevel and csv list of permissions. 无论如何,使用上面的查询将在单行中返回您需要的所有内容:AccessType,AccessLevel和csv权限列表。

 <cfset local.permissionType = qryUserPerm.AccessType>
 <cfset local.permissionLevel = qryUserPerm.AccessLevel>
 <cfset local.permissionList = qryUserPerm.PermissionsList>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM