用于轨道3的Zendesk单点登录宝石

时间:2011-05-10 13:32:25

标签: ruby-on-rails ruby-on-rails-3 zendesk

有没有人知道维护的gem通过现有的Rails 3应用程序处理Zendesk API的用户身份验证?

我向Zendesk IT询问并被发送到https://github.com/tobias/zendesk_remote_auth,但它看起来并不兼容rails 3并且自2009年以来一直没有更新。

2 个答案:

答案 0 :(得分:5)

我认为我们文档中的文章给人的印象是Zendesk SSO很难实际上非常简单(http://www.zendesk.com/api/remote-authentication)。

# reference http://www.zendesk.com/api/remote-authentication
# you need to be a Zendesk account admin to enable remote auth (if you have not already)
# go to Settings > Security, click "Enabled" next to Single Sign-On

# three important things to pay attention to:
# Remote Login URL, Remote Logout URL, and shared secret token

# for testing on a Rails 3 application running on localhost, fill in the Remote Login URL to map
# to http://localhost:3000/zendesk/login (we will need to make sure routes for that exist)

# fill in Remote Logout URL to http://localhost:3000/zendesk/logout

# copy the secret token, you'll need it later


# first, let's create those routes in config/routes.rb
namespace :zendesk do
  match "/login" => "zendesk#login"    # will match /zendesk/login
  match "/logout" => "zendesk#logout"  # will match /zendesk/logout
end

# Above I've mapped those requests to a controller named "zendesk" but it can be named anything

# next we want to add our secret token to the application, I added this in an initializer
# config/initializers/zendesk_auth.rb
ZENDESK_REMOTE_AUTH_TOKEN = "< your token >"
ZENDESK_REMOTE_AUTH_URL   = "http://yourcompany.zendesk.com/access/remote/"

# Assuming we have a controller called zendesk, in zendesk_controller.rb

require "digest/md5"
class ZendeskController < ApplicationController

  def index
    @zendesk_remote_auth_url = ZENDESK_REMOTE_AUTH_URL
  end

  def login
    timestamp = params[:timestamp] || Time.now.utc.to_i
    # hard coded for example purposes
    # really you would want to do something like current_user.name and current_user.email
    # and you'd probably want this in a helper to hide all this implementation from the controller
    string = "First Last" + "first.last@gmail.com" + ZENDESK_REMOTE_AUTH_TOKEN + timestamp.to_s
    hash = Digest::MD5.hexdigest(string)
    @zendesk_remote_auth_url = "http://yourcompany.zendesk.com/access/remote/?name=First%20Last&email=first.last@gmail.com&timestamp=#{timestamp}&hash=#{hash}"
    redirect_to @zendesk_remote_auth_url
  end

  def logout
    flash[:notice] = params[:message]
  end
end

# Note that the above index action defines an instance variable @zendesk_remote_auth_url
# in my example I simple put a link on the corresponding view that hits ZENDESK_REMOTE_AUTH_URL, doing so
# will cause Zendesk to hit your applications Remote Login URL (you defined in your Zendesk SSO settings) and pass a timestamp back in the URL parameters
# BUT, it is entirely possible to avoid this extra step if you just want to go to /zendesk/login in your app
# notice I am either using a params[:timestamp] if one exists or creating a new timestamp with Time.now

这个例子非常简单,但我只是想说明Zendesk SSO的基本机制。请注意,我没有触及创建新用户或编辑现有用户这一更复杂的问题,只需登录拥有现有Zendesk帐户的用户。

答案 1 :(得分:5)

zendesk有一个更新的示例代码

# Using JWT from Ruby is straight forward. The below example expects you to have `jwt`
# in your Gemfile, you can read more about that gem at https://github.com/progrium/ruby-jwt.
# Assuming that you've set your shared secret and Zendesk subdomain in the environment, you
# can use Zendesk SSO from your controller like this example.

class ZendeskSessionController < ApplicationController
  # Configuration
  ZENDESK_SHARED_SECRET = ENV["ZENDESK_SHARED_SECRET"]
  ZENDESK_SUBDOMAIN     = ENV["ZENDESK_SUBDOMAIN"]

  def create
    if user = User.authenticate(params[:login], params[:password])
      # If the submitted credentials pass, then log user into Zendesk
      sign_into_zendesk(user)
    else
      render :new, :notice => "Invalid credentials"
    end
  end

  private

  def sign_into_zendesk(user)
    # This is the meat of the business, set up the parameters you wish
    # to forward to Zendesk. All parameters are documented in this page.
    iat = Time.now.to_i
    jti = "#{iat}/#{rand(36**64).to_s(36)}"

    payload = JWT.encode({
      :iat   => iat, # Seconds since epoch, determine when this token is stale
      :jti   => jti, # Unique token id, helps prevent replay attacks
      :name  => user.name,
      :email => user.email,
    }, ZENDESK_SHARED_SECRET)

    redirect_to zendesk_sso_url(payload)
  end

  def zendesk_sso_url(payload)
    "https://#{ZENDESK_SUBDOMAIN}.zendesk.com/access/jwt?jwt=#{payload}"
  end
end