`
andyhu1007
  • 浏览: 199474 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Rails每周一题(一): Restful Authentication

阅读更多

什么是Restful Authenticaiton:

 

Restful Authentication是Rails的认证系统插件,它为你生成一个REST风格的认证模板。

 

具体的概念和生成操作请见:Rails宝典之六十七式:restful_authentication   , Rails插件:Restful Authenticaiton.

 

本篇为你讲述Restful Authentication的具体实现。

 

认证系统:

 

想象一下,现在大部分网站所提供的认证系统是什么样子的?

 

流程:注册 -》 激活 -》登录 -》登出

 

注册需要什么?    用户名,密码,email。

 

记住我:登录时可以选择记住用户名密码一段时间,在这段时间内不再用输入用户名和密码。

 

这是现在大部分网站的注册和登录系统需要的模板。而只要一个命令,Restful Authentication就为你生成了User model, 管理注册和登录的controller,相应的页面,mailer等等。让我们来看看代码吧。

 

实现:

 

User model:

 

  # attributes相关的代码

  attr_accessor :password    # 不需要保存明文密码到数据库

  validates_presence_of     :login, :email
  validates_presence_of     :password,                   :if => :password_required?
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, :within => 4..40, :if => :password_required?
  validates_confirmation_of :password,                   :if => :password_required?
  validates_length_of       :login,    :within => 3..40
  validates_length_of       :email,    :within => 3..100
  validates_uniqueness_of   :login, :email, :case_sensitive => false
  before_save :encrypt_password  # 为密码加密

  # anything else you want your user to change should be added here.
  # mass assignment
  attr_accessible :login, :email, :password, :password_confirmation

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  protected
    
    def encrypt_password  # 加密密码
      return if password.blank?
      self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
      self.crypted_password = encrypt(password)
    end

     def password_required?  # 当注册时和修改密码时
       crypted_password.blank? || !password.blank?
    end

 

显而易见,这里为大家生成了一个基本的User model,它包含注册所需的一些基本信息,比如用户名,密码,email。并加上了一些简单的validates,以及为密码加密等。

 

# 与激活有关的代码

before_create :make_activation_code   # 创建时生成一个激活码

 # Activates the user in the database.
  def activate    # 激活,把activation_code置为nil
    @activated = true
    self.activated_at = Time.now.utc
    self.activation_code = nil
    save(false)
  end

  def active?
    # the existence of an activation code means they have not activated yet
    activation_code.nil?
  end

  # Returns true if the user has just been activated.
  def recently_activated?
    @activated
  end

 protected

   def make_activation_code
      self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
    end
 

 

  # 与认证有关的代码

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  # 查找数据库是否有相关login的用户存在,并匹配密码。
  def self.authenticate(login, password)
    u = find :first, :conditions => ['login = ? and activated_at IS NOT NULL', login] # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end

   def authenticated?(password)
    crypted_password == encrypt(password)
  end
 

 

  # 与“记住我”相关的代码

  def remember_token?
    remember_token_expires_at && Time.now.utc < remember_token_expires_at 
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    remember_me_for 2.weeks
  end

  def remember_me_for(time)
    remember_me_until time.from_now.utc
  end

  def remember_me_until(time)
    self.remember_token_expires_at = time
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end

 

SessionsController:

 

  # 当remember me时,设置cookie。
  cookies[:auth_token] = { :value => self.current_user.remember_token , 
                                              :expires => self.current_user.remember_token_expires_at }
 

就主要介绍一下model内的代码吧。controller, mailer, observer的代码都比较简单,不再赘述。不过有块代码比较重要,那就是lib下面的AuthenticatedSytem module。

 

这个module里面比较重要的方法有:

 

   # 设置session 
   # Store the given user id in the session.
    def current_user=(new_user)
      session[:user_id] = new_user ? new_user.id : nil
     # 如果认证失败,则赋@current_user为false,避免在获取current_user时再访问数据库
      @current_user = new_user || false
    end

 

 

    # Accesses the current user from the session. 
    # Future calls avoid the database because nil is not equal to false.
    # 此方法将被login_required调用,它会去尝试用三种不同的方式认证。其中第三种直接用客户端存储的
    # auth_token cookied进行认证(即remember me的方式)。
    def current_user
      @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_user == false
    end

    def login_required
      authorized? || access_denied
    end

    def logged_in?
      !!current_user
    end

    def authorized?
      logged_in?
    end

    # Called from #current_user.  First attempt to login by the user id stored in the session.
    def login_from_session
      self.current_user = User.find_by_id(session[:user_id]) if session[:user_id]
    end

    # Called from #current_user.  Now, attempt to login by basic authentication information.
    def login_from_basic_auth
      authenticate_with_http_basic do |username, password|
        self.current_user = User.authenticate(username, password)
      end
    end

    # Called from #current_user.  Finaly, attempt to login by an expiring token in the cookie.
    def login_from_cookie
      user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
      if user && user.remember_token?
        cookies[:auth_token] = { :value => user.remember_token, :expires => user.remember_token_expires_at }
        self.current_user = user
      end
    end
 

代码就讲到这里吧。其实代码挺好懂,可以直接看生成的代码。

 

配置

 

在生成完代码之后,来看看如何进行一些简单的配置。

 

首先是router和observer的配置,很多教程都有。不再赘述。主要讲一下如何给controller设置filter吧。

 

一般在application.rb里面加上这两句,这样所有的controller都需要登录才能访问。

 

 

  include AuthenticatedSystem

  before_filter :login_required

 

当然,你可以为一些controller skip_before_filter。比如UsersController和SessionsController中的一些action就应该skip。

 

关于这个include AuthenticatedSystem,有个很奇妙的地方。

 

我们发现里面的current_user方法不仅在controller里面可以被使用,而且在view里面也可以直接被使用。

 

原来是因为:

 

    # Inclusion hook to make #current_user and #logged_in?
    # available as ActionView helper methods.
    def self.included(base)
      base.send :helper_method, :current_user, :logged_in?
    end
 

 

Rails Session

 

看到这里,可能大家有个疑惑。在Rails里面是怎么直接拿到session的。通过观察,我发现Rails对session已经做了管理。你可以直接看cookie,会发现有一个session_id,它利用这个session_id直接找到你的session。所以,你的使用就如此简单:

 

session[:user_id]
 

完毕

 

分享到:
评论
1 楼 xinghu 2009-07-14  
太好了!学了个底朝天

相关推荐

    关于Rails登录和验证插件http_authentication restful-authentication

    4. **路由(Routing)**: RESTful-Authentication利用Rails的RESTful路由,将URL映射到特定的控制器动作,如/users/login对应于sessions控制器的create动作。 5. **测试(Test)**: 在lib和test目录下,包含着插件的源...

    RESTful.Rails.Development.2015.10.pdf

    根据提供的文件信息,我们可以推断出这是一本关于如何使用Ruby on Rails框架来构建RESTful应用程序和服务的专业书籍。书名为《RESTful Rails Development》,作者为Silvia Puglisi,出版时间为2015年10月。接下来,...

    Rails 3 in Action

    **Rails 3 in Action** 这本书介绍了 **Ruby on Rails**(简称 Rails)这一 Web 开发框架的核心概念和技术细节。Rails 自发布以来便以其优雅、高效、易于使用的特性而闻名,它极大地简化了 Web 应用程序的开发过程。...

    使用rails6开发纯后端API项目.zip

    在Rails 6中开发纯后端API项目是一个常见的任务,特别是在构建现代Web应用程序时,前端与后端分离的架构越来越流行。Rails作为一个强大的Ruby框架,提供了丰富的功能来帮助开发者高效地构建API服务。下面我们将详细...

    Pragmatic.Bookshelf.Advanced.Rails.Recipes.May.2008

    8. **RESTful Design**:REST(Representational State Transfer)是一种架构风格,书中强调了如何遵循REST原则设计优雅的Rails应用。 9. **Rails与ASP.NET、C#、J2EE、Java的比较**:虽然本书主要关注Rails,但也...

    Gobble:Gobble是一个受Slack启发的全栈单页消息传递应用程序。 它在后端使用Ruby on Rails生成RESTful API,在前端使用ReactRedux,并使用Pusher无缝实现WebSockets

    它在后端使用Ruby on Rails生成RESTful API,在前端使用React / Redux,并使用Pusher无缝实现WebSockets。 特征 使用Devise通过自动演示登录进行用户身份验证 即时通讯 讯息格式 通知事项当前频道通知 频道数 直接...

    laravel-token-authentication:Laravel 项目旨在创建和验证通过 RESTful API 使用的令牌

    为此,我们尝试将我们在其他 Web 框架中看到的最好的东西结合起来,包括用其他语言实现的框架,例如 Ruby on Rails、ASP.NET MVC 和 Sinatra。 Laravel易于访问,但功能强大,为大型,强大的应用程序提供了所需的...

    ruby on rails 的小型内容管理系统

    rails2.0的内容管理系统,可以发布文档、CVS库和Web资源3中资源,其中文档可以上传下载附件。支持打Tag。用户注册登录使用restful_authentication,分页使用will_paginate,Gem版本1.3.5

    meetingzero_api:MeetingZero Rails API

    MeetingZero Rails API 是一个基于 Ruby 开发的API接口,它为开发者提供了与MeetingZero平台交互的能力。Ruby是一种面向对象的编程语言,以其简洁、优雅的语法而受到许多Web开发者的喜爱,尤其是对于构建Web服务和...

    angular_practice:这是练习使用Angular和Rails

    6. **Rails API**:在与Angular结合使用时,Rails通常作为API服务器,提供RESTful接口。`config/routes.rb`文件定义了路由规则,`controllers`目录下的文件处理HTTP请求,`models`处理数据模型,而`serializers`用来...

    一个简单的在线投票系统

    5. **RESTful API**:如果前后端分离,后端可能提供RESTful API接口,供前端调用进行数据交换。API设计应遵循统一接口原则,如HTTP动词(GET、POST、PUT、DELETE)对应资源的操作。 6. **安全性**:投票系统的安全...

    RailsAPI

    RailsAPI 是一个专门为构建RESTful API设计的Ruby on Rails框架的子集。它专注于提供一个轻量级的、高效的环境,用于开发仅处理JSON或XML数据的后端服务,而无需传统的Web应用程序视图和路由。RailsAPI的目标是减少...

    Gymify-Backend:这是一个使用Ruby on Rails框架构建的REST API。 该API实现基于令牌的身份验证和授权

    GYMIFY API 使用Ruby on Rails构建的RESTFUL API。 该应用程序公开了健身房前端应用程序的API端点。 该应用程序允许用户注册,登录,查看培训师并与培训师预约约会。终点此api公开了两个端点,可以使用...

    546_api

    2. **资源(Resources):**Rails中的资源路由可以简化RESTful API的创建,通过`resources :controller_name`定义,可以自动生成CRUD操作对应的路由。 3. **控制器(Controllers):**处理请求并返回响应的地方,API的...

    主播电台管理后台.docx

    这可能是一个使用Java、Python、Node.js、Ruby on Rails等后端技术构建的Web服务。 2. **数据库管理**:主播电台的数据,如主播信息、直播记录、用户互动数据等,都需要存储在数据库中。常见的数据库选择有MySQL、...

Global site tag (gtag.js) - Google Analytics