如何设置 angular-rails 4.2 - 设计 registration/authentication?
How to setup angular-rails 4.2 - devise registration/authentication?
你能给点建议或推荐一些与这个主题相关的资源吗?我了解如何在理论上做到这一点。但我也听说过 jwt 等。实现基于 device/angular/rails 角色的 auth/registration 的最佳实践是什么?
简短的回答是阅读这个blog post,其中详细介绍了如何最低限度地实施这个概念
这将是一个很长的代码答案,但我打算写一篇单独的博客 post 来详细介绍如何实现它...
但现在,这是我在某个项目中实现它的方式...
首先是 angular 应用程序部分,您可以使用 Satellizer 之类的东西,播放效果很好...
这里是前端应用中的angular授权模块
# coffeescript
config = (
$authProvider
$stateProvider
) ->
$authProvider.httpInterceptor = true # to automatically add the headers for auth
$authProvider.baseUrl = "http://path.to.your.api/"
$authProvider.loginRedirect = '/profile' # front-end route after login
$authProvider.logoutRedirect = '/' # front-end route after logout
$authProvider.signupRedirect = '/sign_in'
$authProvider.loginUrl = '/auth/sign_in' # api route for sign_in
$authProvider.signupUrl = '/auth/sign_up' # api route for sign_up
$authProvider.loginRoute = 'sign_in' # front-end route for login
$authProvider.signupRoute = 'sign_up' # front-end route for sign_up
$authProvider.signoutRoute = 'sign_out' # front-end route for sign_out
$authProvider.tokenRoot = 'data'
$authProvider.tokenName = 'token'
$authProvider.tokenPrefix = 'front-end-prefix-in-localstorage'
$authProvider.authHeader = 'Authorization'
$authProvider.authToken = 'Bearer'
$authProvider.storage = 'localStorage'
# state configurations for the routes
$stateProvider
.state 'auth',
url: '/'
abstract: true
templateUrl: 'modules/auth/auth.html'
data:
permissions:
only: ['guest']
redirectTo: 'profile'
.state 'auth.sign_up',
url: $authProvider.signupRoute
views:
'sign_up@auth':
templateUrl: 'modules/auth/sign_up.html'
controller: 'AuthenticationCtrl'
controllerAs: 'vm'
.state 'auth.sign_in',
url: $authProvider.loginRoute
views:
'sign_in@auth':
templateUrl: 'modules/auth/sign_in.html'
controller: 'AuthenticationCtrl'
controllerAs: 'vm'
这是satellizer的基本配置...至于认证控制器...类似下面
@signIn = (email, password, remember_me) ->
$auth.login
email: email
password: password
remember_me: remember_me
.then(success, error)
return
@signUp = (name, email, password) ->
$auth.signup
name: name
email: email
password: password
.then(success, error)
return
这是身份验证的基础知识
至于后端 (RoR API),您应该首先允许前端应用程序使用 CORS。并将 gem 'jwt'
添加到您的 gemfile。
其次实施 API 控制器和身份验证控制器
例如,它可能如下所示
class Api::V1::ApiController < ApplicationController
# The API responds only to JSON
respond_to :json
before_action :authenticate_user!
protected
def authenticate_user!
http_authorization_header?
authenticate_request
set_current_user
end
# Bad Request if http authorization header missing
def http_authorization_header?
fail BadRequestError, 'errors.auth.missing_header' unless authorization_header
true
end
def authenticate_request
decoded_token ||= AuthenticationToken.decode(authorization_header)
@auth_token ||= AuthenticationToken.where(id: decoded_token['id']).
first unless decoded_token.nil?
fail UnauthorizedError, 'errors.auth.invalid_token' if @auth_token.nil?
end
def set_current_user
@current_user ||= @auth_token.user
end
# JWT's are stored in the Authorization header using this format:
# Bearer some_random_string.encoded_payload.another_random_string
def authorization_header
return @authorization_header if defined? @authorization_header
@authorization_header =
begin
if request.headers['Authorization'].present?
request.headers['Authorization'].split(' ').last
else
nil
end
end
end
end
class Api::V1::AuthenticationsController < Api::V1::ApiController
skip_before_action :authenticate_user!, only: [:sign_up, :sign_in]
def sign_in
# getting the current user from sign in request
@current_user ||= User.find_by_credentials(auth_params)
fail UnauthorizedError, 'errors.auth.invalid_credentials' unless @current_user
generate_auth_token(auth_params)
render :authentication, status: 201
end
def sign_out
# this auth token is assigned via api controller from headers
@auth_token.destroy!
head status: 204
end
def generate_auth_token(params)
@auth_token = AuthenticationToken.generate(@current_user, params[:remember_me])
end
end
AuthenticationToken
是一种用于跟踪 JWT 令牌的模型(用于像 facebook 这样的会话管理)
这里是 AuthenticationToken
模型的实现
class AuthenticationToken < ActiveRecord::Base
## Relations
belongs_to :user
## JWT wrappers
def self.encode(payload)
AuthToken.encode(payload)
end
def self.decode(token)
AuthToken.decode(token)
end
# generate and save new authentication token for the user
def self.generate(user, remember_me = false)
@auth_token = user.authentication_tokens.create
@auth_token.token = AuthToken.generate(@auth_token.id, remember_me)
@auth_token.save!
@auth_token
end
# check if a token can be used or not
# used by background job to clear the authentication collection
def expired?
AuthToken.decode(token).nil?
end
end
它使用一个名为 AuthToken
的包装器来包装 JWT 功能
这是它的实现
# wrapper around JWT to encapsulate it's code
# and exception handling and don't polute the AuthenticationToken model
class AuthToken
def self.encode(payload)
JWT.encode(payload, Rails.application.secrets.secret_key_base)
end
def self.decode(token)
payload = JWT.decode(token, Rails.application.secrets.secret_key_base)[0]
rescue JWT::ExpiredSignature
# It will raise an error if it is not a token that was generated
# with our secret key or if the user changes the contents of the payload
Rails.logger.info "Expired Token"
nil
rescue
Rails.logger.warn "Invalid Token"
nil
end
def self.generate(token_id, remember_me = false)
exp = remember_me ? 6.months.from_now : 6.hours.from_now
payload = { id: token_id.to_s, exp: exp.to_i }
self.encode(payload)
end
end
你能给点建议或推荐一些与这个主题相关的资源吗?我了解如何在理论上做到这一点。但我也听说过 jwt 等。实现基于 device/angular/rails 角色的 auth/registration 的最佳实践是什么?
简短的回答是阅读这个blog post,其中详细介绍了如何最低限度地实施这个概念
这将是一个很长的代码答案,但我打算写一篇单独的博客 post 来详细介绍如何实现它...
但现在,这是我在某个项目中实现它的方式...
首先是 angular 应用程序部分,您可以使用 Satellizer 之类的东西,播放效果很好...
这里是前端应用中的angular授权模块
# coffeescript
config = (
$authProvider
$stateProvider
) ->
$authProvider.httpInterceptor = true # to automatically add the headers for auth
$authProvider.baseUrl = "http://path.to.your.api/"
$authProvider.loginRedirect = '/profile' # front-end route after login
$authProvider.logoutRedirect = '/' # front-end route after logout
$authProvider.signupRedirect = '/sign_in'
$authProvider.loginUrl = '/auth/sign_in' # api route for sign_in
$authProvider.signupUrl = '/auth/sign_up' # api route for sign_up
$authProvider.loginRoute = 'sign_in' # front-end route for login
$authProvider.signupRoute = 'sign_up' # front-end route for sign_up
$authProvider.signoutRoute = 'sign_out' # front-end route for sign_out
$authProvider.tokenRoot = 'data'
$authProvider.tokenName = 'token'
$authProvider.tokenPrefix = 'front-end-prefix-in-localstorage'
$authProvider.authHeader = 'Authorization'
$authProvider.authToken = 'Bearer'
$authProvider.storage = 'localStorage'
# state configurations for the routes
$stateProvider
.state 'auth',
url: '/'
abstract: true
templateUrl: 'modules/auth/auth.html'
data:
permissions:
only: ['guest']
redirectTo: 'profile'
.state 'auth.sign_up',
url: $authProvider.signupRoute
views:
'sign_up@auth':
templateUrl: 'modules/auth/sign_up.html'
controller: 'AuthenticationCtrl'
controllerAs: 'vm'
.state 'auth.sign_in',
url: $authProvider.loginRoute
views:
'sign_in@auth':
templateUrl: 'modules/auth/sign_in.html'
controller: 'AuthenticationCtrl'
controllerAs: 'vm'
这是satellizer的基本配置...至于认证控制器...类似下面
@signIn = (email, password, remember_me) ->
$auth.login
email: email
password: password
remember_me: remember_me
.then(success, error)
return
@signUp = (name, email, password) ->
$auth.signup
name: name
email: email
password: password
.then(success, error)
return
这是身份验证的基础知识
至于后端 (RoR API),您应该首先允许前端应用程序使用 CORS。并将 gem 'jwt'
添加到您的 gemfile。
其次实施 API 控制器和身份验证控制器
例如,它可能如下所示
class Api::V1::ApiController < ApplicationController
# The API responds only to JSON
respond_to :json
before_action :authenticate_user!
protected
def authenticate_user!
http_authorization_header?
authenticate_request
set_current_user
end
# Bad Request if http authorization header missing
def http_authorization_header?
fail BadRequestError, 'errors.auth.missing_header' unless authorization_header
true
end
def authenticate_request
decoded_token ||= AuthenticationToken.decode(authorization_header)
@auth_token ||= AuthenticationToken.where(id: decoded_token['id']).
first unless decoded_token.nil?
fail UnauthorizedError, 'errors.auth.invalid_token' if @auth_token.nil?
end
def set_current_user
@current_user ||= @auth_token.user
end
# JWT's are stored in the Authorization header using this format:
# Bearer some_random_string.encoded_payload.another_random_string
def authorization_header
return @authorization_header if defined? @authorization_header
@authorization_header =
begin
if request.headers['Authorization'].present?
request.headers['Authorization'].split(' ').last
else
nil
end
end
end
end
class Api::V1::AuthenticationsController < Api::V1::ApiController
skip_before_action :authenticate_user!, only: [:sign_up, :sign_in]
def sign_in
# getting the current user from sign in request
@current_user ||= User.find_by_credentials(auth_params)
fail UnauthorizedError, 'errors.auth.invalid_credentials' unless @current_user
generate_auth_token(auth_params)
render :authentication, status: 201
end
def sign_out
# this auth token is assigned via api controller from headers
@auth_token.destroy!
head status: 204
end
def generate_auth_token(params)
@auth_token = AuthenticationToken.generate(@current_user, params[:remember_me])
end
end
AuthenticationToken
是一种用于跟踪 JWT 令牌的模型(用于像 facebook 这样的会话管理)
这里是 AuthenticationToken
模型的实现
class AuthenticationToken < ActiveRecord::Base
## Relations
belongs_to :user
## JWT wrappers
def self.encode(payload)
AuthToken.encode(payload)
end
def self.decode(token)
AuthToken.decode(token)
end
# generate and save new authentication token for the user
def self.generate(user, remember_me = false)
@auth_token = user.authentication_tokens.create
@auth_token.token = AuthToken.generate(@auth_token.id, remember_me)
@auth_token.save!
@auth_token
end
# check if a token can be used or not
# used by background job to clear the authentication collection
def expired?
AuthToken.decode(token).nil?
end
end
它使用一个名为 AuthToken
的包装器来包装 JWT 功能
这是它的实现
# wrapper around JWT to encapsulate it's code
# and exception handling and don't polute the AuthenticationToken model
class AuthToken
def self.encode(payload)
JWT.encode(payload, Rails.application.secrets.secret_key_base)
end
def self.decode(token)
payload = JWT.decode(token, Rails.application.secrets.secret_key_base)[0]
rescue JWT::ExpiredSignature
# It will raise an error if it is not a token that was generated
# with our secret key or if the user changes the contents of the payload
Rails.logger.info "Expired Token"
nil
rescue
Rails.logger.warn "Invalid Token"
nil
end
def self.generate(token_id, remember_me = false)
exp = remember_me ? 6.months.from_now : 6.hours.from_now
payload = { id: token_id.to_s, exp: exp.to_i }
self.encode(payload)
end
end