Last active
March 22, 2024 04:09
-
-
Save vinsonzou/6ce186914171736becb5e35ebdf806e3 to your computer and use it in GitHub Desktop.
Gitea通过飞书开放平台实现SSO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
通过飞书登录获取用户email字段(用户飞书中必须添加email属性,否则无法登录!!!),如email地址为test@example.com,则gitea用户为test | |
登录后设定cookie,cookie有效期10小时 | |
飞书开放平台的企业自建应用设置: | |
1、配置 安全设置-重定向URL,如此示例中的https://git.example.com | |
2、权限:获取用户邮箱信息 | |
自动注册后,需管理员调整如下信息: | |
1、自定义名称 | |
2、电子邮件地址 | |
3、密码 | |
]] | |
local require = require | |
local ngx = ngx | |
local ngx_re = require "ngx.re" | |
local cjson = require "cjson.safe" | |
local aes = require "resty.aes" | |
local http = require "resty.http" | |
local re_find = ngx.re.find | |
local json_encode = cjson.encode | |
local json_decode = cjson.decode | |
local app_id = "cli_xxx" -- 飞书开放平台企业自建应用app_id | |
local app_secret = "xxx" -- 飞书开放平台企业自建应用app_secret | |
local cookie_key = 'xxx' -- 自定义 | |
local sso_status = ngx.var.cookie_sso_status | |
local token = ngx.shared.token | |
-- only for git clone(http) | |
if re_find(ngx.var.request_uri, [[(git-upload-pack|git-receive-pack)]], "jo") then | |
return | |
end | |
-------------------------- | |
local function getToken() | |
local tenant_access_token = token:get("feishu") | |
if tenant_access_token then | |
return tenant_access_token | |
else | |
local url = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' | |
local payload = {app_id = app_id, app_secret = app_secret} | |
local httpc = http.new() | |
local res, err = httpc:request_uri(url, { | |
method = "POST", | |
body = json_encode(payload), | |
headers = { | |
["Content-Type"] = "application/json; charset=utf-8", | |
} | |
}) | |
if not res then | |
ngx.log(ngx.ERR, 'failed to request: ', err) | |
return | |
end | |
if res.status == 200 then | |
local data = json_decode(res.body) | |
local code = data['code'] | |
if code and code == 0 then | |
local tenant_access_token = data['tenant_access_token'] | |
token:set("feishu", tenant_access_token, 6000) | |
return tenant_access_token | |
end | |
end | |
end | |
end | |
if sso_status then | |
local aes_128_cbc_md5 = aes:new(cookie_key) | |
local auth_user = aes_128_cbc_md5:decrypt(ngx.decode_base64(sso_status)) | |
ngx.var.user = auth_user | |
else | |
local args = ngx.req.get_uri_args() | |
local code = args.code | |
if not code then | |
local redirect_url = "https://open.feishu.cn/open-apis/authen/v1/authorize?app_id=" .. app_id .. "&redirect_uri=https://git.example.com&scope=contact:user.email:readonly" | |
return ngx.redirect(redirect_url) | |
else | |
-- 修复Chrome 123无法登录问题(过滤OPTIONS请求,仅处理GET请求【因code只能被使用一次】) | |
local method = ngx.req.get_method() | |
if method == "OPTIONS" then | |
return ngx.exit(ngx.HTTP_OK) | |
end | |
local tenant_access_token = getToken() | |
local url = 'https://open.feishu.cn/open-apis/authen/v1/access_token' | |
local payload = {grant_type = "authorization_code", code = code} | |
local httpc = http.new() | |
local res, err = httpc:request_uri(url, { | |
method = "POST", | |
body = json_encode(payload), | |
headers = { | |
["Authorization"] = "Bearer ".. tenant_access_token, | |
["Content-Type"] = "application/json; charset=utf-8", | |
} | |
}) | |
if not res then | |
ngx.log(ngx.ERR, 'failed to request: ', err) | |
return | |
end | |
if res.status == 200 then | |
local data = json_decode(res.body) | |
local code = data['code'] | |
if code and code == 0 then | |
local display_name = data['data']['name'] | |
local email = data['data']['email'] | |
local from, to, err = re_find(email, "^[a-z0-9]+@example.com$", "jo") | |
if from then | |
local res, err = ngx_re.split(email, "@") | |
local auth_user = res[1] | |
ngx.var.user = auth_user | |
local aes_128_cbc_md5 = aes:new(cookie_key) | |
local encrypted = aes_128_cbc_md5:encrypt(auth_user) | |
ngx.header['Set-Cookie'] = 'sso_status=' .. ngx.encode_base64(encrypted) .. '; domain=example.com; path=/; SameSite=Lax; Secure; HttpOnly; Expires=' .. ngx.cookie_time(ngx.time()+36000) | |
ngx.log(ngx.ALERT, 'sso success: ', auth_user) | |
else | |
ngx.log(ngx.ERR, 'sso fail: invaild email') | |
return | |
end | |
else | |
ngx.log(ngx.ERR, 'sso fail: ', res.body) | |
return | |
end | |
else | |
ngx.log(ngx.ERR, 'sso request fail: ', res.body) | |
return | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
upstream git_backend { | |
server 127.0.0.1:3000; | |
keepalive 128; | |
} | |
lua_shared_dict token 1m; | |
server { | |
listen 443 ssl http2; | |
ssl_certificate fullchain.pem; | |
ssl_certificate_key privkey.pem; | |
ssl_protocols TLSv1.2 TLSv1.3; | |
ssl_prefer_server_ciphers on; | |
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; | |
ssl_session_timeout 1d; | |
ssl_session_cache shared:SSL:20m; | |
server_name git.example.com; | |
access_log logs/git.access.log main; | |
location / { | |
resolver local=on valid=30s ipv6=off; | |
lua_ssl_verify_depth 1; | |
lua_ssl_trusted_certificate /etc/pki/tls/certs/ca-bundle.crt; | |
set $user ''; | |
access_by_lua_file lua/sso_feishu.lua; | |
proxy_set_header X-WEBAUTH-USER $user; | |
proxy_pass http://git_backend/; | |
proxy_http_version 1.1; | |
proxy_set_header Connection ""; | |
client_max_body_size 10M; | |
} | |
} |
升级至Chrome 123后,cookie必须添加SameSite属性,否则无法设定cookie。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Gitea后端调整配置如下:
[security]
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
[service]
ENABLE_REVERSE_PROXY_AUTHENTICATION = true
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = true