完成了openi单点登录的功能

openi_sso
Alec Zhou 6 years ago
parent e13cbaef60
commit 95e1bc759c

@ -60,6 +60,8 @@ gem 'kaminari'
gem 'elasticsearch-model'
gem 'elasticsearch-rails'
gem 'oauth2'
#Ruby 2.2+ has removed test/unit from the core library.
if RUBY_VERSION>='2.2'
gem 'test-unit', '~> 3.0'

@ -1120,4 +1120,25 @@ class ApplicationController < ActionController::Base
Time.now < Time.new(2019, 4, 23, 2)
end
# 获取Oauth Client
def get_client(site)
client_id = Redmine::Configuration['client_id']
client_secret = Redmine::Configuration['client_secret']
OAuth2::Client.new(client_id, client_secret, site: site)
end
def handle_openi_request
site = Redmine::Configuration['openi_domain']
root_url = Redmine::Configuration['educoder_domain']
get_code_url = "/oauth/get_code"
original_url = request.original_url
client = get_client(site)
redirect_uri = "#{root_url}#{get_code_url}"
authorize_url = client.auth_code.authorize_url(redirect_uri: redirect_uri)
authorize_url = authorize_url + "&gen_code=true&state=1&original_url=#{original_url}"
redirect_to authorize_url
end
end

@ -1,6 +1,5 @@
#encoding: utf-8
class OauthController < ApplicationController
require
include ApplicationHelper
before_filter :user_setup
@ -152,8 +151,65 @@ class OauthController < ApplicationController
render json: user_info.to_json
end
####--Start-- 获取Openi的授权码access_token以及用户信息。为在openi登录的用户创建相关的educoder用户 ####
IDENTITY_SITE = Redmine::Configuration['openi_domain']
ROOT_URL = Redmine::Configuration['educoder_domain']
DEFAULT_PASSWORD = "a12345678"
TOKEN_CALL_BACK = "/oauth/get_token_callback"
USER_INFO = "/oauth/userinfo"
def get_code
# 从OpenI发过来的回调中获取授权码
code = params[:code]
# 利用授权码从OpenI这里获取access_token
client = get_client(IDENTITY_SITE)
redirect_uri = "#{ROOT_URL}#{TOKEN_CALL_BACK}"
access_token_hash = client.auth_code.get_token(code, redirect_uri: redirect_uri).to_hash
# 利用access_token获取OpenI的用户信息
access_token = access_token_hash[:access_token]
get_info_url = "#{IDENTITY_SITE}#{USER_INFO}?access_token=#{access_token}"
response = HTTParty.get(get_info_url)
body_json = JSON.parse response.body
openi_user_id = body_json['token']
avatar_url = body_json['avatar_url']
login = body_json['login']
name = body_json['name']
email = body_json['email']
# 根据获取的用户信息来查询数据库如已经存在对应的Educoder用户则直接访问用户要访问的实训页面否则为其创建用户后再访问实训页面
openi = Openi.find_by_login(login)
unless openi
ActiveRecord::Base.transaction do
user = User.new(lastname: name, mail: email, mail_notification: email)
user.login = custom_openi_login(login)
user.password = DEFAULT_PASSWORD
user.save!
UserExtensions.create!(user_id: user.id, school_id: School.first.id, identity: 4, gender: 0)
UserDayCertification.create!(user_id: user.id, status: 1)
openi = Openi.create!(user_id: user.id, openi_user_id: openi_user_id, avatar_url: avatar_url, login: login, name: name, email: email)
end
end
self.logged_user = openi.user
original_url = params[:original_url]
redirect_to original_url
end
def get_token_callback
end
####--End-- 获取Openi的授权码access_token以及用户信息。为在openi登录的用户创建相关的educoder用户 ####
private
# 为了保证新创建的用户用户名不与系统中已存在的用户冲突,加上 _openi 后缀
def custom_openi_login(login)
login + "_openi"
end
def require_login
require "base64"

@ -2,6 +2,8 @@
# REDO: 创建版本库权限控制
class ShixunsController < ApplicationController
layout 'base_shixun'
# 如要添加或修改before_filter时请将handle_openi_request这个before_filter放至第一位
before_filter :handle_openi_request, if: -> {URI(request.referer).host == 'openi.org.cn' && !current_user.logged?}
before_filter :require_login, :except => [:ghook, :download_file, :show, :index]
before_filter :check_authentication, :except => [:ghook, :download_file, :show, :index]
before_filter :find_shixun, :except => [ :index, :new, :create, :index, :search, :shixun_courses, :new_disscuss, :shixun_migrate, :qrcode, :download_file, :departments, :get_mirror_script, :send_message_to_administrator]

@ -1,6 +1,8 @@
# encoding: utf-8
class SubjectsController < ApplicationController
layout 'base_subject'
# 如要添加或修改before_filter时请将handle_openi_request这个before_filter放至第一位
before_filter :handle_openi_request, if: -> {URI(request.referer).host == 'openi.org.cn' && !current_user.logged?}
before_filter :require_login, :except => [:show, :index]
before_filter :check_authentication, :except => [:show, :index]
before_filter :find_subject, :except => [:index, :new, :create, :create_subject, :new_subject, :append_to_stage, :send_to_course]

@ -0,0 +1,8 @@
class Openi < ActiveRecord::Base
attr_accessible :allow, :avatar_url, :email, :login, :name, :openi_user_id, :user_id
belongs_to :user
def self.find_by_login(login)
Openi.where(login: login).first
end
end

@ -33,6 +33,9 @@ RedmineApp::Application.routes.draw do ## oauth相关
match 'oauth/cb', to: 'oauth#test_callback', :via => :get
match 'oauth/userinfo', to: 'oauth#get_userinfo', :via => :get
match 'oauth/get_code', to: 'oauth#get_code', :via => :get
match 'oauth/get_token_callback', to: 'oauth#get_token_callback', :via => :get
get 'ecloud/ecloud_login', to: 'ecloud#ecloud_login_callback'
post 'ecloud/bs_new', to: 'ecloud#bs_new'
post 'ecloud/bs_update', to: 'ecloud#bs_update'

@ -0,0 +1,15 @@
class CreateOpenis < ActiveRecord::Migration
def change
create_table :openis do |t|
t.integer :user_id
t.integer :openi_user_id
t.string :login
t.string :avatar_url
t.string :name
t.string :email
t.integer :allow
t.timestamps
end
end
end

@ -0,0 +1,11 @@
FactoryGirl.define do
factory :openi do
user_id 1
openi_user_id 1
login "MyString"
avatar_url "MyString"
name "MyString"
email "MyString"
allow 1
end
end

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe Openi, :type => :model do
pending "add some examples to (or delete) #{__FILE__}"
end
Loading…
Cancel
Save