What is a common approach to scope records by those that an user can “read”?

后端 未结 5 744
太阳男子
太阳男子 2020-12-21 13:11

I am using Ruby on Rails 3.2.2 and I would like to know what is a common approach when it must be checked if an user has proper authorizations to \"read\" records present in

相关标签:
5条回答
  • 2020-12-21 13:26

    I think you sholud look for declarative_authorization gem. With its with_permissions_to method you can easily perfom such database queries. For example: Article.with_permissions_to(:read).limit(10).offset(20)

    0 讨论(0)
  • 2020-12-21 13:32

    The cancan gem has this functionality. In fact, as of version 1.4 it will automatically scope your queries to return objects that are accessible to the current user.

    See this page for more info: https://github.com/ryanb/cancan/wiki/Fetching-Records

    0 讨论(0)
  • 2020-12-21 13:32

    For best performance I would suggest storing list of user readable articles in the session - the user is not going to change within the session and you may consider refresh frequency and/or conditions separately. Assuming that your Articles.list() can be filtered by ids all you will need to do will be to pass the list of user readable ids to Articles.list() functionality. Re user readable list update: you should really update it relatively infrequently - at most once per search, you don' t want to refresh the complete list on every page load for the simple reason that the new results may appear in the pages that user already scrolled through anyway.

    0 讨论(0)
  • 2020-12-21 13:40

    It depends on your readable_by_user function. If it is easy to translate into an SQL, than it is the way forward. If it is more complicated than that then you most probably have to do the check manually.

    UPDATE: To clarify the point of creating an SQL query for the readable list I present an example. Assume, that a readability of an article to a given user is dependent of the following:

    • The user's own article (SELECT a.user == ? FROM Articles a WHERE a.id = ?)
    • The article is open to everyone (SELECT a.state == 0 FROM Articles a WHERE a.user = ?)
    • The user is member of a group with access to articles

    sql:

    SELECT max(g.rights) > 64
    FROM Groups g 
    JOIN Groups_users gu on g.id = ug.group_id
    WHERE gu.id = ?
    
    • The user is assigned to the given article

    sql:

    SELECT 1
    FROM Articles_users au
    WHERE au.article_id = ? AND au.user_id = ?
    

    These can be summarized in the following query:

    def articles_for_user(user) 
      Articles.find_by_sql(["
        SELECT a.*
        FROM Articles a
        LEFT OUTER JOIN Articles_users au on au.article_id = a.id and au.user_id = ?
        WHERE a.user_id = ? 
           OR au.user_id = ?
           OR 64 <= (SELECT max(g.rights) 
                     FROM Groups g 
                     JOIN Groups_users gu on g.id = ug.group_id
                     WHERE gu.id = ?)
      ", user.id, user.id, user.id, user.id])
    end
    

    This is sure a complicated query, but the most efficient solution. The database should do database stuff, if you only use SQL queries and some logic to evaluate your readable_bu_user then you can translate it into one pure SQL query.

    0 讨论(0)
  • 2020-12-21 13:40

    I had the same issue on a system I'm currently worked on.

    The most efficient way I found was to implement a batch job that pre-calculates the authorization state of each record. I went with something like accessible_by_companies and stored an array with all the company codes that could access those records, but you might as well work with accessible_by_users if that's your case.

    On the "show" action, I recalculate the list of authorized companies for the record, use it to perform the authorization check, and store it again.

    I used ElasticSearch to store the pre-calculated values and all the data I needed to perform queries and listings. The database is only touched when viewing a record or by the batch job. There's a big performance gain on this approach, give it a try.

    0 讨论(0)
提交回复
热议问题