| @@ -118,6 +118,10 @@ gem 'deep_cloneable', '~> 3.0.0' | |||||
| # oauth2 | # oauth2 | ||||
| gem 'omniauth', '~> 1.9.0' | gem 'omniauth', '~> 1.9.0' | ||||
| gem 'omniauth-oauth2', '~> 1.6.0' | gem 'omniauth-oauth2', '~> 1.6.0' | ||||
| gem "omniauth-github" | |||||
| gem "omniauth-rails_csrf_protection" | |||||
| gem 'omniauth-gitee', '~> 1.0.0' | |||||
| gem "omniauth-wechat-oauth2" | |||||
| # global var | # global var | ||||
| gem 'request_store' | gem 'request_store' | ||||
| @@ -11,7 +11,7 @@ module LoginHelper | |||||
| def set_autologin_cookie(user) | def set_autologin_cookie(user) | ||||
| token = Token.get_or_create_permanent_login_token(user, "autologin") | token = Token.get_or_create_permanent_login_token(user, "autologin") | ||||
| sync_user_token_to_trustie(user.login, token.value) | |||||
| # sync_user_token_to_trustie(user.login, token.value) | |||||
| Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" | Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" | ||||
| cookie_options = { | cookie_options = { | ||||
| @@ -1,14 +1,21 @@ | |||||
| module RegisterHelper | module RegisterHelper | ||||
| extend ActiveSupport::Concern | extend ActiveSupport::Concern | ||||
| def autologin_register(username, email, password, platform= 'forge') | |||||
| def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false) | |||||
| result = {message: nil, user: nil} | result = {message: nil, user: nil} | ||||
| email = email.blank? ? "#{username}@example.org" : email | |||||
| user = User.new(admin: false, login: username, mail: email, type: "User") | user = User.new(admin: false, login: username, mail: email, type: "User") | ||||
| user.password = password | user.password = password | ||||
| user.platform = platform | user.platform = platform | ||||
| user.activate | |||||
| user.phone = phone if phone.present? | |||||
| user.nickname = nickname if nickname.present? | |||||
| if need_edit_info | |||||
| user.need_edit_info | |||||
| else | |||||
| user.activate | |||||
| end | |||||
| return unless user.valid? | return unless user.valid? | ||||
| interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | ||||
| @@ -36,7 +43,7 @@ module RegisterHelper | |||||
| user.password = params[:password] | user.password = params[:password] | ||||
| user.mail = params[:email] | user.mail = params[:email] | ||||
| if user.save! | |||||
| if user.save! | |||||
| sync_params = { | sync_params = { | ||||
| password: params[:password].to_s, | password: params[:password].to_s, | ||||
| email: params[:email], | email: params[:email], | ||||
| @@ -44,9 +51,9 @@ module RegisterHelper | |||||
| new_name: params[:username], | new_name: params[:username], | ||||
| source_id: 0 | source_id: 0 | ||||
| } | } | ||||
| interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params) | interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params) | ||||
| if interactor.success? | |||||
| if interactor.success? | |||||
| result[:user] = user | result[:user] = user | ||||
| else | else | ||||
| result[:message] = '用户同步Gitea失败!' | result[:message] = '用户同步Gitea失败!' | ||||
| @@ -2,6 +2,7 @@ class Oauth::BaseController < ActionController::Base | |||||
| include RenderHelper | include RenderHelper | ||||
| include LoginHelper | include LoginHelper | ||||
| include ControllerRescueHandler | include ControllerRescueHandler | ||||
| include RegisterHelper | |||||
| # include LaboratoryHelper | # include LaboratoryHelper | ||||
| skip_before_action :verify_authenticity_token | skip_before_action :verify_authenticity_token | ||||
| @@ -22,7 +23,7 @@ class Oauth::BaseController < ActionController::Base | |||||
| end | end | ||||
| def auth_hash | def auth_hash | ||||
| Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") | |||||
| # Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") | |||||
| request.env['omniauth.auth'] | request.env['omniauth.auth'] | ||||
| end | end | ||||
| @@ -0,0 +1,65 @@ | |||||
| class Oauth::CallbacksController < Oauth::BaseController | |||||
| def create | |||||
| process_callback | |||||
| rescue Exception => e | |||||
| tip_exception("授权失败") | |||||
| end | |||||
| private | |||||
| def config_providers | |||||
| config = Rails.application.config_for(:configuration) | |||||
| config.dig("oauth").keys | |||||
| end | |||||
| # QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"} | |||||
| def process_callback | |||||
| Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") | |||||
| if auth_hash.blank? | |||||
| redirect_to("/login") && return | |||||
| end | |||||
| new_user = false | |||||
| platform = auth_hash[:provider] | |||||
| uid = auth_hash[:uid] | |||||
| mail = auth_hash.info.email || nil | |||||
| nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname | |||||
| open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid) | |||||
| if open_user.present? && open_user.user.present? | |||||
| successful_authentication(open_user.user) | |||||
| else | |||||
| if current_user.blank? || !current_user.logged? | |||||
| has_user = User.find_by(mail: mail) | |||||
| if has_user.present? | |||||
| "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra) | |||||
| successful_authentication(has_user) | |||||
| else | |||||
| new_user = true | |||||
| login = build_login_name(platform, auth_hash.info.nickname) | |||||
| mail = "#{login}@example.org" if mail.blank? | |||||
| reg_result = autologin_register(login, mail, "Ec#{login}2022#", platform, nil, nickname) | |||||
| Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ") | |||||
| if reg_result[:message].blank? | |||||
| open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra) | |||||
| successful_authentication(open_user.user) | |||||
| else | |||||
| tip_exception(reg_result.present? ? reg_result[:message] : "授权失败") | |||||
| end | |||||
| end | |||||
| else | |||||
| "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra) | |||||
| end | |||||
| end | |||||
| redirect_to root_path(new_user: new_user) | |||||
| end | |||||
| # gitee,github nickname=login,如果系统未占用保留原用户名 | |||||
| def build_login_name(provider, nickname) | |||||
| if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank? | |||||
| nickname | |||||
| else | |||||
| User.generate_user_login('p') | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,27 @@ | |||||
| # == Schema Information | |||||
| # | |||||
| # Table name: open_users | |||||
| # | |||||
| # id :integer not null, primary key | |||||
| # user_id :integer | |||||
| # type :string(255) | |||||
| # uid :string(255) | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # extra :text(65535) | |||||
| # | |||||
| # Indexes | |||||
| # | |||||
| # index_open_users_on_type_and_uid (type,uid) UNIQUE | |||||
| # index_open_users_on_user_id (user_id) | |||||
| # | |||||
| class OpenUsers::Gitee < OpenUser | |||||
| def nickname | |||||
| extra&.[]('nickname') | |||||
| end | |||||
| def en_type | |||||
| 'gitee' | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,27 @@ | |||||
| # == Schema Information | |||||
| # | |||||
| # Table name: open_users | |||||
| # | |||||
| # id :integer not null, primary key | |||||
| # user_id :integer | |||||
| # type :string(255) | |||||
| # uid :string(255) | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # extra :text(65535) | |||||
| # | |||||
| # Indexes | |||||
| # | |||||
| # index_open_users_on_type_and_uid (type,uid) UNIQUE | |||||
| # index_open_users_on_user_id (user_id) | |||||
| # | |||||
| class OpenUsers::Github < OpenUser | |||||
| def nickname | |||||
| extra&.[]('name') | |||||
| end | |||||
| def en_type | |||||
| 'github' | |||||
| end | |||||
| end | |||||
| @@ -113,7 +113,7 @@ class User < Owner | |||||
| # trustie: 来自Trustie平台 | # trustie: 来自Trustie平台 | ||||
| # forge: 平台本身注册的用户 | # forge: 平台本身注册的用户 | ||||
| # military: 军科的用户 | # military: 军科的用户 | ||||
| enumerize :platform, in: [:forge, :educoder, :trustie, :military], default: :forge, scope: :shallow | |||||
| enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat], default: :forge, scope: :shallow | |||||
| belongs_to :laboratory, optional: true | belongs_to :laboratory, optional: true | ||||
| has_one :user_extension, dependent: :destroy | has_one :user_extension, dependent: :destroy | ||||
| @@ -774,6 +774,15 @@ class User < Owner | |||||
| login | login | ||||
| end | end | ||||
| # 生成数字账号 | |||||
| CODES = %W(0 1 2 3 4 5 6 7 8 9) | |||||
| def self.generate_user_login type | |||||
| code = CODES.sample(8).join | |||||
| code = type + code.to_s | |||||
| return User.generate_user_login(type) if User.where(login: code).present? | |||||
| code | |||||
| end | |||||
| def bind_open_user?(type) | def bind_open_user?(type) | ||||
| case type | case type | ||||
| when 'wechat' then wechat_open_user.present? | when 'wechat' then wechat_open_user.present? | ||||
| @@ -1,21 +1,27 @@ | |||||
| OmniAuth.config.add_camelization 'qq', 'QQ' | |||||
| config = Rails.application.config_for(:configuration) | |||||
| OmniAuth.config.add_camelization 'qq', 'QQ' if config.dig("oauth", "qq") | |||||
| OmniAuth.config.add_camelization 'github', 'GitHub' if config.dig("oauth", "github") | |||||
| OmniAuth.config.add_camelization 'gitee', 'Gitee' if config.dig("oauth", "gitee") | |||||
| OmniAuth.config.add_camelization 'wechat', 'Wechat' if config.dig("oauth", "wechat") | |||||
| OmniAuth.config.logger = Rails.logger | OmniAuth.config.logger = Rails.logger | ||||
| OmniAuth.config.before_request_phase = nil | |||||
| OmniAuth.config.before_callback_phase = nil | |||||
| OmniAuth.config.on_failure = Proc.new { |env| | OmniAuth.config.on_failure = Proc.new { |env| | ||||
| OmniAuth::FailureEndpoint.new(env).redirect_to_failure | OmniAuth::FailureEndpoint.new(env).redirect_to_failure | ||||
| } | } | ||||
| oauth_config = {} | |||||
| begin | |||||
| config = Rails.application.config_for(:configuration) | |||||
| oauth_config = config.dig('oauth', 'qq') | |||||
| raise 'oauth qq config missing' if oauth_config.blank? | |||||
| rescue => ex | |||||
| raise ex if Rails.env.production? | |||||
| puts %Q{\033[33m [warning] qq oauth config or configuration.yml missing, | |||||
| please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} | |||||
| end | |||||
| Rails.application.config.middleware.use OmniAuth::Builder do | Rails.application.config.middleware.use OmniAuth::Builder do | ||||
| provider :qq, oauth_config['appid'], oauth_config['secret'], { provider_ignores_state: true } | |||||
| if config.dig("oauth", "qq") | |||||
| provider :qq, config.dig("oauth", "qq", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true } | |||||
| end | |||||
| if config.dig("oauth", "github").present? | |||||
| provider :github, config.dig("oauth", "github", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true, scope: "user:email" } | |||||
| end | |||||
| if config.dig("oauth", "gitee").present? | |||||
| provider :gitee, config.dig("oauth", "gitee", "appid"), config.dig("oauth", "gitee", "secret"), { provider_ignores_state: true, scope: "user_info emails" } | |||||
| end | |||||
| if config.dig("oauth", "wechat").present? | |||||
| provider :gitee, config.dig("oauth", "wechat", "appid"), config.dig("oauth", "wechat", "secret"), { provider_ignores_state: true, scope: "snsapi_login" } | |||||
| end | |||||
| end | end | ||||
| @@ -0,0 +1,7 @@ | |||||
| # frozen_string_literal: true | |||||
| # Be sure to restart your server when you modify this file. | |||||
| # Enable per-form CSRF tokens. | |||||
| # Rails.application.config.action_controller.per_form_csrf_tokens = true | |||||
| # Rails.application.config.action_controller.forgery_protection_origin_check = true | |||||
| @@ -23,6 +23,7 @@ Rails.application.routes.draw do | |||||
| get 'auth/qq/callback', to: 'oauth/qq#create' | get 'auth/qq/callback', to: 'oauth/qq#create' | ||||
| get 'auth/failure', to: 'oauth/base#auth_failure' | get 'auth/failure', to: 'oauth/base#auth_failure' | ||||
| get 'auth/cas/callback', to: 'oauth/cas#create' | get 'auth/cas/callback', to: 'oauth/cas#create' | ||||
| get 'auth/:provider/callback', to: 'oauth/callbacks#create' | |||||
| get 'oauth/bind', to: 'oauth/educoder#bind' | get 'oauth/bind', to: 'oauth/educoder#bind' | ||||
| get 'oauth/register', to: 'oauth#register' | get 'oauth/register', to: 'oauth#register' | ||||