| @@ -0,0 +1,78 @@ | |||
| html{margin:0px;padding: 0px;font-size: 14px;font-family: "微软雅黑","宋体";} | |||
| body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { | |||
| margin: 0; | |||
| padding: 0; | |||
| } | |||
| .IndexContent{ | |||
| height: 100vh; | |||
| width: 100%; | |||
| position: relative; | |||
| background-image: url('/images/oauth/backImg.png'); | |||
| background-repeat: no-repeat; | |||
| background-size: cover; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| flex-direction: column; | |||
| } | |||
| .indexLogo{ | |||
| width:80px; | |||
| margin-bottom: 35px; | |||
| } | |||
| .indexPanel{ | |||
| width: 580px; | |||
| min-height: 400px; | |||
| background-color: #fff; | |||
| box-shadow: 0px 2px 10px 5px rgba(0,0,0,0.05); | |||
| border-radius: 5px; | |||
| box-sizing: border-box; | |||
| } | |||
| .indexTitle{ | |||
| height: 75px; | |||
| line-height: 75px; | |||
| font-size: 18px; | |||
| color:#333; | |||
| text-align: center; | |||
| border-bottom: 1px solid #eee; | |||
| } | |||
| .indexInfo{ | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: flex-start; | |||
| } | |||
| .indexInfos{ | |||
| padding:40px 60px; | |||
| } | |||
| .indexInfo > span{ | |||
| color: #333; | |||
| font-size: 16px; | |||
| margin-top: 5px; | |||
| } | |||
| .indexInfo input{ | |||
| width: 100%; | |||
| height:40px; | |||
| border-radius: 2px; | |||
| border:1px solid #eee; | |||
| margin-top: 5px; | |||
| padding:0px 0px 0px 8px; | |||
| outline: none; | |||
| } | |||
| .indexInfo .checkInfo{ | |||
| height: 15px; | |||
| color: red; | |||
| } | |||
| .indexBtn{ | |||
| text-align: center; | |||
| margin-top: 20px; | |||
| } | |||
| .indexSubmit{ | |||
| width: 50%; | |||
| height: 32px; | |||
| line-height: 32px; | |||
| background-color: #1890FF; | |||
| border:none; | |||
| color: #fff; | |||
| border-radius: 2px; | |||
| cursor: pointer; | |||
| outline: none; | |||
| } | |||
| @@ -13,24 +13,12 @@ class AccountsController < ApplicationController | |||
| password = params[:password] | |||
| platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") | |||
| @user = User.new(admin: false, login: username, mail: email, type: "User") | |||
| @user.password = password | |||
| @user.platform = platform | |||
| @user.activate | |||
| ActiveRecord::Base.transaction do | |||
| interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | |||
| if interactor.success? | |||
| gitea_user = interactor.result | |||
| result = Gitea::User::GenerateTokenService.new(username, password).call | |||
| @user.gitea_token = result['sha1'] | |||
| @user.gitea_uid = gitea_user['id'] | |||
| if @user.save! | |||
| UserExtension.create!(user_id: @user.id) | |||
| render_ok({user: {id: @user.id, token: @user.gitea_token}}) | |||
| end | |||
| result = autologin_register(username, email, password, platform) | |||
| if result[:message].blank? | |||
| render_ok({user: result[:user]}) | |||
| else | |||
| render_error(interactor.error) | |||
| render_error(result[:message]) | |||
| end | |||
| end | |||
| rescue Exception => e | |||
| @@ -9,7 +9,8 @@ class ApplicationController < ActionController::Base | |||
| include GitHelper | |||
| include LoggerHelper | |||
| include LoginHelper | |||
| include RegisterHelper | |||
| protect_from_forgery prepend: true, unless: -> { request.format.json? } | |||
| before_action :check_sign | |||
| @@ -0,0 +1,28 @@ | |||
| module RegisterHelper | |||
| extend ActiveSupport::Concern | |||
| def autologin_register(username, email, password, platform= '') | |||
| result = {message: nil, user: nil} | |||
| user = User.new(admin: false, login: username, mail: email, type: "User") | |||
| user.password = password | |||
| user.platform = platform | |||
| user.activate | |||
| interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | |||
| if interactor.success? | |||
| gitea_user = interactor.result | |||
| result = Gitea::User::GenerateTokenService.new(username, password).call | |||
| user.gitea_token = result['sha1'] | |||
| user.gitea_uid = gitea_user['id'] | |||
| if user.save! | |||
| UserExtension.create!(user_id: user.id) | |||
| result[:user] = {id: user.id, token: user.gitea_token} | |||
| end | |||
| else | |||
| result[:message] = interactor.error | |||
| end | |||
| result | |||
| end | |||
| end | |||
| @@ -0,0 +1,36 @@ | |||
| class Oauth::EducoderController < Oauth::BaseController | |||
| def bind | |||
| begin | |||
| login = params[:login] | |||
| callback_url = params[:callback_url] | |||
| oauth_token = params[:key] | |||
| raw_pay_load = params[:raw_pay_load] | |||
| ::OauthEducoderForm.new({login: login, oauth_token: oauth_token, callback_url: callback_url, raw_pay_load: raw_pay_load}).validate! | |||
| open_user= OpenUser::Educoder.find_by(uid: login) | |||
| if open_user.present? && open_user.user.present? && open_user.user.email_bind? | |||
| # 存在说明绑定了,验证信息是否齐全, | |||
| if current_user != open_user.user | |||
| logout_user | |||
| successful_authentication(open_user.user) | |||
| end | |||
| redirect_to callback_url | |||
| else | |||
| # 未存在需要进行绑定 | |||
| if current_user.blank? || !current_user.logged? | |||
| # forge平台未登录 | |||
| redirect_to oauth_register_path(user_id: login, callback_url: callback_url) | |||
| else | |||
| # forge平台已登录 | |||
| OpenUsers::Educoder.create!(user: current_user, uid: login) | |||
| redirect_to callback_url | |||
| end | |||
| end | |||
| rescue WechatOauth::Error => ex | |||
| render_error(ex.message) | |||
| end | |||
| end | |||
| end | |||
| @@ -1,4 +1,6 @@ | |||
| class OauthController < ApplicationController | |||
| layout "oauth_register", only: [:register] | |||
| DEFAULT_PASSWORD = "a12345678" | |||
| TOKEN_CALL_BACK = "/oauth/get_token_callback" | |||
| USER_INFO = "/oauth/userinfo" | |||
| @@ -51,4 +53,24 @@ class OauthController < ApplicationController | |||
| def get_token_callback | |||
| end | |||
| def register | |||
| # redirect_to params[:callback_url] | |||
| end | |||
| def auto_register | |||
| login = params[:login] | |||
| email = params[:email] | |||
| password = params[:login] | |||
| platform = params[:plathform] || 'forge' | |||
| result = autologin_register(login, email, password, platform) | |||
| if result[:message].blank? | |||
| redirect_to params[:callback_url] | |||
| else | |||
| render :action => "auto_register" | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,37 @@ | |||
| class OauthEducoderForm | |||
| include ActiveModel::Model | |||
| attr_accessor :login, :oauth_token, :callback_url, :raw_pay_load | |||
| validates :login, presence: true | |||
| validates :oauth_token, presence: true | |||
| validates :callback_url, presence: true | |||
| validates :raw_pay_load, presence: true | |||
| validate :check_oauth_token! | |||
| validate :check_callback_url! | |||
| def checke_raw_pay_load! | |||
| secret = OauthEducoder.config[:access_key_secret] | |||
| before_raw_pay_load = "#{login}#{secret}#{Time.now.to_i/60-1}" | |||
| now_raw_pay_load = "#{login}#{secret}#{Time.now.to_i/60-1}" | |||
| if raw_pay_load != Digest::SHA1.hexdigest(now_raw_pay_load) || raw_pay_load != Digest::SHA1.hexdigest(before_raw_pay_load) | |||
| raise '你的请求无效值无效.' | |||
| end | |||
| end | |||
| def checke_raw_pay_load! | |||
| secret = OauthEducoder.config[:access_key_secret] | |||
| raise 'oauth_token值无效.' if oauth_token != secret | |||
| end | |||
| def check_callback_url! | |||
| request_host = URI.parse(callback_url).host | |||
| callback_url = OauthEducoder.config[:callback_url_host] | |||
| raise 'callback_url参数无效.' if request_host != callback_url | |||
| end | |||
| end | |||
| @@ -0,0 +1,20 @@ | |||
| module OauthEducoder | |||
| class << self | |||
| def config | |||
| educoder_config = {} | |||
| begin | |||
| config = Rails.application.config_for(:configuration).symbolize_keys! | |||
| educoder_config = config[:oauth][:educoder].symbolize_keys! | |||
| raise 'oauth educoder config missing' if educoder_config.blank? | |||
| rescue => ex | |||
| raise ex if Rails.env.production? | |||
| puts %Q{\033[33m [warning] educoder config or configuration.yml missing, | |||
| please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} | |||
| educoder_config = {} | |||
| end | |||
| educoder_config | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,9 @@ | |||
| class OpenUsers::EduCoder < OpenUser | |||
| def nickname | |||
| extra&.[]('nickname') | |||
| end | |||
| def en_type | |||
| 'educoder' | |||
| end | |||
| end | |||
| @@ -0,0 +1,13 @@ | |||
| <html> | |||
| <head> | |||
| <%= csrf_meta_tags %> | |||
| <%= csp_meta_tag %> | |||
| <%= stylesheet_link_tag 'oauth', media: 'all','data-turbolinks-track': 'reload' %> | |||
| </head> | |||
| <body> | |||
| <div class="IndexContent"> | |||
| <%= image_tag('/images/oauth/logo.png') %> | |||
| <%= yield %> | |||
| </div> | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,54 @@ | |||
| <div class="indexPanel"> | |||
| <p class="indexTitle">完善信息,进入比赛</p> | |||
| <div class="indexInfos"> | |||
| <%= form_tag(oauth_auto_register_path, method: :post, class: 'form-inline search-form flex-1') do %> | |||
| <%= hidden_field_tag 'callback_url', params[:callback_url] %> | |||
| <div class="indexInfo"> | |||
| <span>用户名:</span> | |||
| <%= text_field_tag :mail, params[:login], placeholder: '请输入用户名', disabled: true, id: 'login' %> | |||
| <p class="checkInfo loginCheck"><span></span></p> | |||
| </div> | |||
| <div class="indexInfo"> | |||
| <span>邮箱:</span> | |||
| <%= text_field_tag :mail, '', placeholder: '请输入绑定邮箱', maxlength: 40, id: 'email' %> | |||
| <p class="checkInfo emailCheck"><span></span></p> | |||
| </div> | |||
| <div class="indexInfo"> | |||
| <span>密码:</span> | |||
| <%= password_field_tag :password, '', placeholder: '请输入账号密码', id: 'password' %> | |||
| <p class="checkInfo passwordCheck"><span></span></p> | |||
| </div> | |||
| <div class="indexBtn"> | |||
| <button class="indexSubmit" onclick="sureSubmit();">确定</button> | |||
| </div> | |||
| <% end %> | |||
| </div> | |||
| </div> | |||
| <script type="text/javascript"> | |||
| function sureSubmit(){ | |||
| var login = $("#login").val(); | |||
| var email = $("#email").val(); | |||
| var password = $("#password").val(); | |||
| alert(email) | |||
| if(!login){ | |||
| $(".loginCheck span").html("请输入账号"); | |||
| return; | |||
| }else{ | |||
| $(".loginCheck span").html(""); | |||
| } | |||
| if(!login){ | |||
| $(".loginCheck span").html("请输入账号"); | |||
| return; | |||
| }else{ | |||
| $(".emailCheck span").html(""); | |||
| } | |||
| if(!password){ | |||
| $(".passwordCheck span").html("请输入账号密码"); | |||
| return; | |||
| }else{ | |||
| $(".passwordCheck span").html(""); | |||
| } | |||
| } | |||
| </script> | |||
| @@ -12,5 +12,4 @@ Rails.application.config.assets.paths << Rails.root.join('vendor/assets') | |||
| # Precompile additional assets. | |||
| # application.js, application.css, and all non-JS/CSS in the app/assets | |||
| # folder are already added. | |||
| Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css cooperative.js cooperative.css ) | |||
| Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css cooperative.js cooperative.css oauth.css ) | |||
| @@ -13,6 +13,11 @@ Rails.application.routes.draw do | |||
| get 'auth/qq/callback', to: 'oauth/qq#create' | |||
| get 'auth/failure', to: 'oauth/base#auth_failure' | |||
| get 'auth/cas/callback', to: 'oauth/cas#create' | |||
| get 'oauth/bind', to: 'oauth/educoder#bind' | |||
| get 'oauth/register', to: 'oauth#register' | |||
| post 'oauth/auto_register', to: 'oauth#auto_register' | |||
| resources :edu_settings | |||
| scope '/api' do | |||