রেলগুলিতে অনন্য টোকেন তৈরির সর্বোত্তম উপায়?


156

আমি যা ব্যবহার করছি তা এখানে। টোকেনটি অনুমান করার জন্য অগত্যা শোনা উচিত নয়, এটি অন্য যে কোনও কিছুর চেয়ে শর্ট ইউআরএল সনাক্তকারীটির মতো এবং আমি এটিকে ছোট রাখতে চাই। আমি অনলাইনে পেয়েছি এমন কয়েকটি উদাহরণ অনুসরণ করেছি এবং সংঘর্ষের ঘটনায় আমি মনে করি নীচের কোডটি টোকেনটি পুনরায় তৈরি করবে, তবে আমি সত্যই নিশ্চিত নই। আমি আরও ভাল পরামর্শ দেখতে আগ্রহী, যদিও এটি প্রান্তের চারপাশে কিছুটা রুক্ষ বোধ করে।

def self.create_token
    random_number = SecureRandom.hex(3)
    "1X#{random_number}"

    while Tracker.find_by_token("1X#{random_number}") != nil
      random_number = SecureRandom.hex(3)
      "1X#{random_number}"
    end
    "1X#{random_number}"
  end

টোকেনের জন্য আমার ডাটাবেস কলামটি একটি অনন্য সূচক এবং আমি validates_uniqueness_of :tokenমডেলটিও ব্যবহার করছি , তবে এগুলি অ্যাপ্লিকেশনটিতে কোনও ব্যবহারকারীর ক্রিয়াকলাপের ভিত্তিতে ব্যাচগুলিতে স্বয়ংক্রিয়ভাবে তৈরি করা হয়েছে (তারা একটি অর্ডার দেয় এবং মূলত টোকেনগুলি কিনে), এটি it's অ্যাপটিতে ত্রুটি ছুঁড়ে ফেলা সম্ভব নয়।

আমি অনুমান করতে পারি, সংঘর্ষের সম্ভাবনা হ্রাস করতে, শেষে অন্য একটি স্ট্রিং সংযোজন করতে হবে, সময় বা সেই জাতীয় কিছুটির উপর ভিত্তি করে তৈরি কিছু, তবে আমি টোকনটি বেশি দীর্ঘ পেতে চাই না।

উত্তর:


333

-- হালনাগাদ --

এর হিসাবে 9 ম জানুয়ারি 2015. সমাধান এখন বাস্তবায়িত হয় পাগল 5 ActiveRecord এর সুরক্ষা টোকেন বাস্তবায়ন

- রেল 4 এবং 3 -

কেবল ভবিষ্যতের রেফারেন্সের জন্য, নিরাপদ র্যান্ডম টোকন তৈরি করা এবং এটি মডেলের জন্য স্বতন্ত্রতা নিশ্চিত করা (রুবি ১.৯ এবং অ্যাক্টিভেকর্ড ব্যবহার করার সময়):

class ModelName < ActiveRecord::Base

  before_create :generate_token

  protected

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64(nil, false)
      break random_token unless ModelName.exists?(token: random_token)
    end
  end

end

সম্পাদনা:

@kain প্রস্তাব, এবং আমি রাজি প্রতিস্থাপন begin...end..whileসঙ্গে loop do...break unless...endএই উত্তরটি কারণ পূর্ববর্তী বাস্তবায়ন ভবিষ্যতে সরানো হতে পারে।

সম্পাদনা 2:

রেল 4 এবং উদ্বেগগুলির সাথে, আমি এটিকে উদ্বেগের দিকে নিয়ে যাওয়ার পরামর্শ দিচ্ছি।

# app/models/model_name.rb
class ModelName < ActiveRecord::Base
  include Tokenable
end

# app/models/concerns/tokenable.rb
module Tokenable
  extend ActiveSupport::Concern

  included do
    before_create :generate_token
  end

  protected

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64(nil, false)
      break random_token unless self.class.exists?(token: random_token)
    end
  end
end

শুরু ব্যবহার করবেন না / যখন, ব্যবহার লুপ / না
Kain

@ কেইন কোনও কারণ loop do("যখন ... ডুপ " ধরণের লুপ) ব্যবহার করা উচিত (যেখানে লুপের ধরণটি "কমপক্ষে একবার চালানো প্রয়োজন) এর পরিবর্তে begin...while(" লুপের ধরণ "করবেন)?
ক্রুলে

7
এলোমেলো টোটেন লুপের মধ্যে স্কোপযুক্ত হওয়ায় এই সঠিক কোডটি কাজ করবে না।
জোনাথন মুই

1
@ ক্রুল এখন আপনি এটিকে কনসার্নে পরিণত করেছেন, আপনিও কি এই ModelNameপদ্ধতিতে পরিত্রাণ পাবেন না ? পরিবর্তে এটি সঙ্গে প্রতিস্থাপন করতে পারেন self.class? অন্যথায়, এটি খুব পুনরায় ব্যবহারযোগ্য নয়, তাই না?
প্যারিসিলে

1
সমাধান অবচিত করা হয় না, নিরাপদ টোকেন এটি সহজভাবে পাগল 5 বাস্তবায়িত হয়, কিন্তু এটা পাগল 4 ব্যবহার করা যাবে না বা 3 পাগল (যা এই প্রশ্ন সম্পর্কিত পর্যন্ত)
Aleks

52

রায়ান বেটস বিটা আমন্ত্রণে তার রেইলকাস্টে একটি দুর্দান্ত সামান্য কোড ব্যবহার করে । এটি একটি 40 অক্ষরের আলফানিউমেরিক স্ট্রিং তৈরি করে।

Digest::SHA1.hexdigest([Time.now, rand].join)

3
হ্যাঁ, এটি খারাপ নয়। আমি সাধারণত একটি URL এর অংশ হিসাবে ব্যবহার করার জন্য অনেক ছোট স্ট্রিং সন্ধান করছি।
স্লিক 23

হ্যাঁ, এটি কমপক্ষে পড়া এবং বুঝতে সহজ। 40 টি চরিত্র কিছু পরিস্থিতিতে ভাল (যেমন বিটা আমন্ত্রণগুলি) এবং এটি আমার জন্য এখনও ভাল কাজ করছে।
নেট বার্ড

12
@ স্লিক 23 আপনি সর্বদা স্ট্রিংয়ের একটি অংশও দখল করতে পারেন:Digest::SHA1.hexdigest([Time.now, rand].join)[0..10]
বিজন

গুগল অ্যানালিটিক্সের পরিমাপ প্রোটোকলে "ক্লায়েন্ট আইডি" প্রেরণের সময় আমি আইপি ঠিকানাগুলি অস্পষ্ট করতে এটি ব্যবহার করি। এটি একটি ইউইউডি হওয়ার কথা, তবে আমি hexdigestকোনও প্রদত্ত আইপি- র জন্য প্রথম 32 টি অক্ষর গ্রহণ করি ।
thekingoftruth

1
৩২-বিটের আইপি ঠিকানার জন্য, @ থেকিংফ্রথ দ্বারা উত্পাদিত যে কোনও সম্ভাব্য হেক্সডিজাস্টের সমস্তের একটি সন্ধানের টেবিল পাওয়া মোটামুটি সহজ, সুতরাং কেউ এই ভেবেও যান না যে এমনকি হ্যাশের একটি স্তরও অপরিবর্তনীয় হবে।
mwfearnley

32

এটি দেরিতে প্রতিক্রিয়া হতে পারে তবে একটি লুপ ব্যবহার এড়ানোর জন্য আপনি পদ্ধতিটিকে পুনরাবৃত্তভাবে কল করতে পারেন। এটি দেখতে আমার কাছে কিছুটা ক্লিনার মনে হয় এবং লাগে।

class ModelName < ActiveRecord::Base

  before_create :generate_token

  protected

  def generate_token
    self.token = SecureRandom.urlsafe_base64
    generate_token if ModelName.exists?(token: self.token)
  end

end

30

এই নিবন্ধে প্রদর্শিত এই কাজ করার কিছু চমত্কার উপায় আছে:

https://web.archive.org/web/20121026000606/http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-ruby

আমার তালিকাভুক্ত প্রিয়টি হ'ল:

rand(36**8).to_s(36)
=> "uur0cj2h"

দেখে মনে হচ্ছে প্রথম পদ্ধতিটি আমি যা করছি তার অনুরূপ, তবে আমি ভেবেছিলাম র্যান্ড ডেটাবেস অজ্ঞানী ছিল না?
স্লিক 23

এবং আমি নিশ্চিত নই যে আমি এটি অনুসরণ করেছি: if self.new_record? and self.access_token.nil?... টোকন ইতিমধ্যে সংরক্ষণ করা হয়নি তা নিশ্চিত করার জন্য এটি কি পরীক্ষা করছে?
স্লিক 23

4
বিদ্যমান টোকেনগুলির বিরুদ্ধে আপনার সর্বদা অতিরিক্ত চেকের প্রয়োজন হবে। আমি বুঝতে পারিনি যে এটি সুস্পষ্ট নয়। validates_uniqueness_of :tokenমাইগ্রেশন সহ কেবল টেবিলটিতে একটি অনন্য সূচক যুক্ত করুন এবং যুক্ত করুন ।
কোরওয়্যার

6
লেখক এখানে ব্লগ পোস্ট! হ্যাঁ: আমি সর্বদা একটি ডিবি সীমাবদ্ধতা বা এই ক্ষেত্রে ইউনিটটি দৃity় করার অনুরূপ যোগ করি।
থাইবাট ব্যারারে

1
যারা পোস্ট খুঁজছেন তাদের জন্য (যার আর অস্তিত্ব নেই) ... web.archive.org/web/20121026000606/http://blog.logeek.fr/2009/7/…
কিং'রি মাইনা

17

আপনি যদি এমন কিছু চান যা অনন্য হবে আপনি এই জাতীয় কিছু ব্যবহার করতে পারেন:

string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")

তবে এটি 32 টি অক্ষরের স্ট্রিং উত্পন্ন করবে।

অন্য উপায় আছে:

require 'base64'

def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end

উদাহরণস্বরূপ 10000 মত আইডির জন্য, উত্পন্ন টোকেনটি "এমটিএইচএমডিএ =" এর মতো হবে (এবং আপনি সহজেই এটি আইডির জন্য ডিকোড করতে পারেন, কেবল তৈরি করুন

Base64::decode64(string)

আমি নিশ্চিত হয়েছি যে উত্পন্ন মানটি অনন্য স্ট্রিং তৈরির পদ্ধতির পরিবর্তে ইতিমধ্যে উত্পন্ন এবং সঞ্চিত মানগুলির সাথে সংঘর্ষ না করবে।
স্লিক 23

উত্পন্ন মানটি ইতিমধ্যে উত্পন্ন মানগুলির সাথে সংঘর্ষ করবে না - বেস 64৪ হ'ল নির্জনবাদী, সুতরাং আপনার যদি অনন্য আইড থাকে তবে আপনার অনন্য টোকেন থাকবে।
এ্যাসে

আমি random_string = Digest::MD5.hexdigest("#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}-#{id}")[1..6]যেখানে গিয়েছিলাম সেই আইডিটি টোকেনের আইডি।
স্লিক 23

11
আমার কাছে মনে হচ্ছে এটি Base64::encode64(id.to_s)একটি টোকেন ব্যবহারের উদ্দেশ্যকে পরাস্ত করে। সম্ভবত আপনি আইডিটিকে অস্পষ্ট করতে এবং টোকেনটি নেই এমন যেকোন ব্যক্তির পক্ষে সংস্থানটি অ্যাক্সেসযোগ্য করার জন্য একটি টোকেন ব্যবহার করছেন। যাইহোক, এই ক্ষেত্রে, কেউ কেবল চালাতে পারে Base64::encode64(<insert_id_here>)এবং তাদের তত্ক্ষণাত আপনার সাইটের প্রতিটি সংস্থার জন্য সমস্ত টোকেন রাখে।
জন লেমন

কাজ করার জন্য এটিতে পরিবর্তিত হওয়া দরকারstring = (Digest::MD5.hexdigest "#{SecureRandom.hex(10)}-#{DateTime.now.to_s}")
কাসিম

14

এটি সহায়ক হতে পারে:

SecureRandom.base64(15).tr('+/=', '0aZ')

প্রথম আর্গুমেন্ট '+ / =' রাখার চেয়ে যদি আপনি কোনও বিশেষ অক্ষর এবং মুছে ফেলতে চান তবে দ্বিতীয় আর্গুমেন্ট '0 এজেড' এবং 15 এ দেওয়া কোনও অক্ষর এখানে দৈর্ঘ্য।

এবং যদি আপনি অতিরিক্ত স্পেস এবং নতুন লাইনের চরিত্রটি বাদ দিতে চান তবে এই জাতীয় জিনিসগুলি যুক্ত করুন:

SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n")

আশা করি এটি যে কাউকে সহায়তা করবে।


3
আপনি যদি "+ / =" এর মতো অদ্ভুত অক্ষর না চান তবে আপনি বেস 64 এর পরিবর্তে সিকিউরর্যান্ডম.হেক্স (10) ব্যবহার করতে পারেন।
মিন মিং লো

16
SecureRandom.urlsafe_base64একই জিনিস অর্জন।
iterion

7

আপনি ব্যবহারকারীদের_সিকিউর_ টোকেন https://github.com/robertomiranda/has_secure_token করতে পারেন

ব্যবহার করা সত্যিই সহজ

class User
  has_secure_token :token1, :token2
end

user = User.create
user.token1 => "44539a6a59835a4ee9d7b112b48cd76e"
user.token2 => "226dd46af6be78953bde1641622497a8"

সুন্দরভাবে মোড়ানো! ধন্যবাদ: ডি
এমএসভিসজকজ

1
আমি স্থানীয় 'ভেরিয়েবল' has_secure_token 'অপরিবর্তিত। কোন ধারণা কেন?
অ্যাড্রিয়ান মাত্তিও

3
@ অ্যাড্রিয়ানম্যাটিওও আমার একই সমস্যা ছিল। আমি যা বুঝতে পেরেছি সেগুলি থেকে has_secure_tokenরেল 5 আসবে তবে আমি 4.x ব্যবহার করছিলাম। আমি এই নিবন্ধের পদক্ষেপগুলি অনুসরণ করেছি এবং এখন এটি আমার পক্ষে কাজ করে।
তামারা বার্নাদ


5

একটি সঠিক, মাইএসকিএল, বারচর 32 জিইউডি তৈরি করতে

SecureRandom.uuid.gsub('-','').upcase

যেহেতু আমরা একটি একক অক্ষর '-' প্রতিস্থাপনের চেষ্টা করছি, আপনি gsub এর পরিবর্তে tr ব্যবহার করতে পারেন। SecureRandom.uuid.tr('-','').upcase। টিআর এবং জিএসবির মধ্যে তুলনার জন্য এই লিঙ্কটি পরীক্ষা করুন
শ্রীরাজ

2
def generate_token
    self.token = Digest::SHA1.hexdigest("--#{ BCrypt::Engine.generate_salt }--")
end

0

আমি মনে করি টোকেন ঠিক পাসওয়ার্ডের মতো পরিচালনা করা উচিত। এর মতো, তাদের ডিবিতে এনক্রিপ্ট করা উচিত।

মডেলের জন্য একটি অনন্য নতুন টোকেন উত্পন্ন করতে আমি এই জাতীয় কিছু করছি:

key = ActiveSupport::KeyGenerator
                .new(Devise.secret_key)
                .generate_key("put some random or the name of the key")

loop do
  raw = SecureRandom.urlsafe_base64(nil, false)
  enc = OpenSSL::HMAC.hexdigest('SHA256', key, raw)

  break [raw, enc] unless Model.exist?(token: enc)
end
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.