|
|
|
|
#encoding: utf-8
|
|
|
|
|
class OauthController < ApplicationController
|
|
|
|
|
require
|
|
|
|
|
include ApplicationHelper
|
|
|
|
|
|
|
|
|
|
before_filter :user_setup
|
|
|
|
|
before_filter :require_login, only: [:authorize]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skip_before_filter :verify_authenticity_token, only: [:token]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def index
|
|
|
|
|
render 'oauth/index', layout: false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 客户端申请认证的URI,包含以下参数:
|
|
|
|
|
#
|
|
|
|
|
# response_type:表示授权类型,必选项,此处的值固定为”code”
|
|
|
|
|
# client_id:表示客户端的ID,必选项
|
|
|
|
|
# redirect_uri:表示重定向URI,可选项
|
|
|
|
|
# scope:表示申请的权限范围,可选项
|
|
|
|
|
# state:表示客户端的当前状态,可以指定任意值(最好是随机字符串),认证服务器会原封不动地返回这个值,可防止CSRF攻击
|
|
|
|
|
#
|
|
|
|
|
# 这个页显示授权页,如果授权成功,返回redirect_uri+code
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
# 服务器回应客户端的URI,包含以下参数:
|
|
|
|
|
#
|
|
|
|
|
# code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次, 否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
|
|
|
|
|
# state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
|
|
|
|
|
def authorize
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
|
#参数检查
|
|
|
|
|
raise "response_type只能为code" unless params["response_type"] == "code"
|
|
|
|
|
raise "client_id为必传项" unless params["client_id"].present?
|
|
|
|
|
raise "redirect_uri为必传项" unless params["redirect_uri"].present?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
config = OauthConfig.where(client_id: params["client_id"], redirect_uri: params["redirect_uri"]).first
|
|
|
|
|
raise "client_id或redirect_uri不正确" unless config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@data = params
|
|
|
|
|
|
|
|
|
|
if params[:gen_code]
|
|
|
|
|
## 检查通过,生成code
|
|
|
|
|
oauth = Oauth.create!(client_id: config.client_id,
|
|
|
|
|
client_secret: config.client_secret,
|
|
|
|
|
redirect_uri: config.redirect_uri,
|
|
|
|
|
user_id: User.current.id
|
|
|
|
|
)
|
|
|
|
|
code = oauth.gen_code
|
|
|
|
|
|
|
|
|
|
redirect_to params["redirect_uri"] + "?code=#{code}&state=#{params[:state]}"
|
|
|
|
|
else
|
|
|
|
|
render 'oauth/authorize', :layout => 'forge'
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
rescue => e
|
|
|
|
|
logger.error e
|
|
|
|
|
render :text => e.message
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def test_callback
|
|
|
|
|
# 申请 token
|
|
|
|
|
#
|
|
|
|
|
client_id = "88d893c5a345313e7b8c6fcf23d3d024ee08d5e41ce120c3448b6eea77d8de30"
|
|
|
|
|
client_secret = "e9240cc5fc913741db5aea93f2986a8ea0631bb67f7c00e41e491b95d9619e64"
|
|
|
|
|
redirect_uri = "http://localhost:3000/oauth/cb"
|
|
|
|
|
url = "http://127.0.0.1:3000/oauth/token?grant_type=authorization_code&code=#{params['code']}&redirect_uri=#{redirect_uri}&client_id=#{client_id}&client_secret=#{client_secret}"
|
|
|
|
|
|
|
|
|
|
render text: url
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 客户端向认证服务器申请令牌的HTTP请求,包含以下参数:
|
|
|
|
|
#
|
|
|
|
|
# grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
|
|
|
|
|
# code:表示上一步获得的授权码,必选项。
|
|
|
|
|
# redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
|
|
|
|
|
# client_id:表示客户端ID,必选项。
|
|
|
|
|
# client_secret: 表示客户端密钥,必选项。
|
|
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
# 认证服务器核对了授权码和”重定向URI”,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
|
|
|
|
|
#
|
|
|
|
|
# 认证服务器发送的HTTP回复,包含以下内容:
|
|
|
|
|
#
|
|
|
|
|
# access_token:表示访问令牌,必选项。
|
|
|
|
|
# token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
|
|
|
|
|
# expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
|
|
|
|
|
# refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
|
|
|
|
|
# scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
|
|
|
|
|
def token
|
|
|
|
|
begin
|
|
|
|
|
res = {}
|
|
|
|
|
if params[:grant_type] == 'authorization_code'
|
|
|
|
|
|
|
|
|
|
raise "code必传" unless params["code"]
|
|
|
|
|
raise "client_id必传" unless params["client_id"]
|
|
|
|
|
raise "client_secret必传" unless params["client_secret"]
|
|
|
|
|
|
|
|
|
|
raise "code错误或已超时" unless Oauth.code_valid?(params["code"])
|
|
|
|
|
|
|
|
|
|
oauth = Oauth.auth_code(params["code"], params["client_id"], params["client_secret"])
|
|
|
|
|
raise "认证不通过" unless oauth
|
|
|
|
|
|
|
|
|
|
## 生成 token
|
|
|
|
|
#
|
|
|
|
|
oauth.gen_token
|
|
|
|
|
|
|
|
|
|
oauth.reload
|
|
|
|
|
|
|
|
|
|
res = {
|
|
|
|
|
access_token: oauth.access_token,
|
|
|
|
|
token_type: 'bearer',
|
|
|
|
|
expires_in: oauth.token_expires_in,
|
|
|
|
|
refresh_token: oauth.refresh_token
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
render json: res.to_json
|
|
|
|
|
|
|
|
|
|
rescue => e
|
|
|
|
|
logger.error e
|
|
|
|
|
render text: e.message
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_userinfo
|
|
|
|
|
user = Oauth.auth(params["access_token"])
|
|
|
|
|
|
|
|
|
|
user_info = {}
|
|
|
|
|
if user
|
|
|
|
|
user_info = {
|
|
|
|
|
token: user.id,
|
|
|
|
|
login: user.login,
|
|
|
|
|
avatar_url: "https://openi.org.cn/images/" + url_to_avatar(user),
|
|
|
|
|
name: user.show_name,
|
|
|
|
|
email: user.mail,
|
|
|
|
|
allow: (user.login == "guange"||user.phone=='15607313899') ? 1 : 0
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
render json: user_info.to_json
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
|
|
def require_login
|
|
|
|
|
require "base64"
|
|
|
|
|
if !User.current.logged?
|
|
|
|
|
redirect_to '/login?back_url64=' + Base64.urlsafe_encode64(request.original_url)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
include Trustie::Http
|
|
|
|
|
|
|
|
|
|
end
|