开发者

Excluding private data in RESTful response

What is the best practice for excluding certain fields/data in a RESTful response if the user requesting it shouldn't be able to see all of the data?

Example:

Person has a First Name, Last Name, and Date of Birth.

Both authenticated and non-authenticated users can make RESTful requests to /people.xml to get a full list of people. However, only authenticated users should be able to view all of the information. Non-authenticated users should only have the First and Last Name fields returned (excluding the Date Of Birth data).

Should the Person controller check for authentication before building the response? If user is authenticated they get ev开发者_开发技巧erything, else they only get a subset? Does that break any rules of REST where /people.xml can send two separate results?


No, that's fine. It's the same resource, but with a different representations based on the authentication information. You could also serve different versions depending on what the Accept header contained (you should use that one instead of file extensions like .xml, by the way), or you could serve different language versions, or you could render the page different if the logged in user has specific personalization options defined. It's all legal. Consider a website that has a login box. If you're logged in, the page will be different. That's the same thing, except it doesn't specifically affect the enclosed information per se. Controlling caching and so forth in these cases is exactly what Cache-Control, Vary and friends are for. Also see http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications


The same URL can yield different representations, depending on the request-headers. For example, Accept is commonly used to control the format of the response (f.ex. XML or JSON). Likewise, authentication-headers could be used to control how much is returned for an entity.


You can use the :only option of the to_xml method to restrict the fields returned by the controller, i.e.:

def show
  @person = Person.find(params[:id])
  payload = current_user.nil? ? @person.to_xml(:only => 
                  [:first_name, :last_name, :dob]) : @person

  respond_to do |format|
    format.xml  { render :xml => payload }  
  end    
end

I use serialize_with_options plugin, as most of the view data access configuration can be done at the model level.

class Person
  serialize_with_options(:anonymous) do
    only   :first_name, :last_name, :dob
  end
end


class PersonController
  def show
    @person = Person.find(:params[:id])
    respond_to do |format|
      format.xml { render :xml => current_user.nil? ? @person.to_xml(:anonymous):
                             @person   }
    end    
  end
end

Reference

1 serialize_with_options


Consider that different representations of the same data (depending on the user) could have surprising consequences if you have a cache somewhere in the middle. If the fully authenticated user makes the request first, then followed by the 'lesser' user, they might see surprising result: The same view as the fully authenticated user before. That's because there is no difference in the two requests as far as the cache is concerned (unless you make it aware of these issues). So, tread carefully.

I would also suggest separate namespaces, as proposed by Robert.


By the book, REST says that one resource should return the same result every request.

I would create a namespace with "unauthenticated" or something and make

/people.xml for authenticated

and

/unauthenticated/people.xml

They could be the same controller building different xml results for each request.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜