国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

開發(fā)一個網(wǎng)站的步驟推廣軟件賺錢的app

開發(fā)一個網(wǎng)站的步驟,推廣軟件賺錢的app,網(wǎng)絡(luò)營銷服務(wù)外包,電商門戶網(wǎng)站這陣子不是deepseek火么?我也折騰了下本地部署,ollama、vllm、llama.cpp都弄了下,webui也用了幾個,發(fā)現(xiàn)nextjs-ollama-llm-ui小巧方便,挺適合個人使用的。如果放在網(wǎng)上供多人使用的話,得接入登錄認(rèn)證才好&a…

這陣子不是deepseek火么?我也折騰了下本地部署,ollama、vllm、llama.cpp都弄了下,webui也用了幾個,發(fā)現(xiàn)nextjs-ollama-llm-ui小巧方便,挺適合個人使用的。如果放在網(wǎng)上供多人使用的話,得接入登錄認(rèn)證才好,不然所有人都能蹭玩,這個可不太妙。
我是用openresty反向代理將webui發(fā)布出去的,有好幾種方案實(shí)現(xiàn)接入外部登錄認(rèn)證系統(tǒng)。首先是直接修改nextjs-ollama-llm-ui的源碼,其實(shí)我就是這么做的,因為這樣接入能將登錄用戶信息帶入應(yīng)用,可以定制頁面,將用戶顯示在頁面里,體驗會更好。其次openresty是支持auth_request的,你需要編碼實(shí)現(xiàn)幾個web接口就可以了,進(jìn)行簡單配置即可,這種方式也很靈活,邏輯你自行編碼實(shí)現(xiàn)。還有一種就是在openresty里使用lua來對接外部認(rèn)證系統(tǒng),也就是本文要介紹的內(nèi)容。
在折騰的過程中,開始是想利用一些現(xiàn)有的輪子,結(jié)果因為偷懶反而踩了不少坑。包括但不限于openssl、session,后來一想,其實(shí)也沒有多難,手搓也不復(fù)雜。
首先是這樣設(shè)計的,用戶的標(biāo)識信息寫入cookie,比如用一個叫做SID的字段,其構(gòu)成為時間戳+IP,aes加密后的字符串;當(dāng)用戶的IP發(fā)生變化或者其他客戶端偽造cookie訪問,openresty可以識別出來,歸類到未認(rèn)證用戶,跳轉(zhuǎn)到認(rèn)證服務(wù)器(帶上回調(diào)url)。

location /webui {content_by_lua_block {local resty_string = require "resty.string"local resty_aes = require "resty.aes"local key = "1234567890123456"  -- 16 bytes key for AES-128local iv = "1234567890123456"   -- 16 bytes IV for AES-128local aes = resty_aes:new(key, nil, resty_aes.cipher(128, "cbc"), {iv=iv})local redis = require "resty.redis"local red = redis:new()red:set_timeouts(1000, 1000, 1000)  -- 連接超時、發(fā)送超時、讀取超時local ok, err = red:connect("127.0.0.1", 6379)if not ok thenngx.say("Failed to connect to Redis: ", err)returnendfunction get_client_ip()local headers = ngx.req.get_headers()local client_ip-- 優(yōu)先從 X-Forwarded-For 獲取local x_forwarded_for = headers["X-Forwarded-For"]if x_forwarded_for thenclient_ip = x_forwarded_for:match("([^,]+)")end-- 如果 X-Forwarded-For 不存在,嘗試從 X-Real-IP 獲取if not client_ip thenclient_ip = headers["X-Real-IP"]end-- 如果以上都不存在,回退到 remote_addrif not client_ip thenclient_ip = ngx.var.remote_addrendreturn client_ipendlocal function hex_to_bin(hex_str)-- 檢查輸入是否為有效的十六進(jìn)制字符串if not hex_str or hex_str:len() % 2 ~= 0 thenreturn nil, "Invalid hex string: length must be even"endlocal bin_data = ""for i = 1, #hex_str, 2 do-- 每兩個字符表示一個字節(jié)local byte_str = hex_str:sub(i, i + 1)-- 將十六進(jìn)制字符轉(zhuǎn)換為數(shù)字local byte = tonumber(byte_str, 16)if not byte thenreturn nil, "Invalid hex character: " .. byte_strend-- 將數(shù)字轉(zhuǎn)換為對應(yīng)的字符bin_data = bin_data .. string.char(byte)endreturn bin_dataendlocal cookies = ngx.var.http_Cookieif cookies thenlocal my_cookie = ngx.re.match(cookies, "sid=([^;]+)")if my_cookie thenlocal ckv=my_cookie[1]local ckvr=hex_to_bin(ckv)local decrypted = aes:decrypt(ckvr)local getip=string.sub(decrypted,12)if getip ~= get_client_ip() thenreturn ngx.exit(ngx.HTTP_BAD_REQUEST)endlocal userinfo, err = red:get(ckv)if not userinfo thenreturn ngx.redirect('https://sso.yourdomain.com/oauth2/authorize?redirect_uri=https://webapp.yourdomain.com/sso/callback')endelsereturn ngx.redirect('https://sso.yourdomain.com/oauth2/authorize?redirect_uri=https://webapp.yourdomain.com/sso/callback')end}proxy_pass   http://127.0.0.1:3000;
}...

用戶認(rèn)證信息是存放在后端redis中,key是SID,value是認(rèn)證訪問返回的userid,在認(rèn)證成功后寫入,看是否需要在用戶注銷時主動刪除記錄??梢栽趎ginx.conf里添加logout路徑,但是可能需要在相關(guān)頁面中放進(jìn)去才好工作,否則用戶估計不會在瀏覽器中手工輸入logout的url來注銷的??梢栽赾ookie設(shè)置時設(shè)定有效時長,在redis添加記錄時設(shè)置有效時長。

-- callback
location /callback {content_by_lua_block {local http = require "resty.http"-- 獲取授權(quán)碼local args = ngx.req.get_uri_args()local code = args.codelocal state = args.state-- 驗證 stateif state ~= "some_random_state" thenngx.status = ngx.HTTP_BAD_REQUESTngx.say("Invalid state")return ngx.exit(ngx.HTTP_BAD_REQUEST)end-- 獲取 access tokenlocal httpc = http.new()local res, err = httpc:request_uri("https://sso.yourdomain.com/oauth2/token", {method = "POST",body = ngx.encode_args({code = code,client_id = "YOUR_CLIENT_ID",client_secret = "YOUR_CLIENT_SECRET",grant_type = "authorization_code"}),headers = {["Content-Type"] = "application/x-www-form-urlencoded"}})if not res thenngx.status = ngx.HTTP_INTERNAL_SERVER_ERRORngx.say("Failed to request token: ", err)return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)endlocal token = res.body.access_token-- 獲取用戶信息local res, err = httpc:request_uri("https://sso.yourdomain.com/oauth2/v1/userinfo", {method = "GET",body = ngx.encode_args({client_id = "YOUR_CLIENT_ID",accesstoken = token}),})if not res thenngx.status = ngx.HTTP_INTERNAL_SERVER_ERRORngx.say("Failed to request user info: ", err)return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)endlocal user_info = res.bodylocal redis = require "resty.redis"local red = redis:new()red:set_timeouts(1000, 1000, 1000)  -- 連接超時、發(fā)送超時、讀取超時local ok, err = red:connect("127.0.0.1", 6379)if not ok thenngx.say("Failed to connect to Redis: ", err)returnendfunction get_client_ip()local headers = ngx.req.get_headers()local client_ip-- 優(yōu)先從 X-Forwarded-For 獲取local x_forwarded_for = headers["X-Forwarded-For"]if x_forwarded_for thenclient_ip = x_forwarded_for:match("([^,]+)")end-- 如果 X-Forwarded-For 不存在,嘗試從 X-Real-IP 獲取if not client_ip thenclient_ip = headers["X-Real-IP"]end-- 如果以上都不存在,回退到 remote_addrif not client_ip thenclient_ip = ngx.var.remote_addrendreturn client_ipendlocal timestamp = os.time()local text = timestamp ..":"..get_client_ip()local resty_string = require "resty.string"local resty_aes = require "resty.aes"local key = "1234567890123456"  -- 16 bytes key for AES-128local iv = "1234567890123456"   -- 16 bytes IV for AES-128local aes = resty_aes:new(key, nil, resty_aes.cipher(128, "cbc"), {iv=iv})local encrypted = aes:encrypt(text)local my_value=resty_string.to_hex(encrypted)ngx.header["Set-Cookie"] = "sid=" .. my_value .. "; Path=/; Expires=" .. ngx.cookie_time(ngx.time() + 14400) .. "; HttpOnly"local key = my_valuelocal value = user_info.useridlocal expire_time = 14400  -- 四小時后過期local res, err = red:set(key, value, "EX", expire_time)if not res thenngx.say("Failed to set key: ", err)returnend-- 重定向到受保護(hù)的頁面ngx.redirect("/webui")}
}

其實(shí)也有現(xiàn)成的oauth2的輪子,不過我們自己手寫lua代碼的話,可以更靈活的配置,對接一些非標(biāo)準(zhǔn)的web認(rèn)證服務(wù)也可以的。

http://m.aloenet.com.cn/news/39025.html

相關(guān)文章:

  • 廣州移動 網(wǎng)站設(shè)計如何在各大平臺推廣
  • 天津建設(shè)工程信息網(wǎng)如何注冊網(wǎng)站優(yōu)化推廣招聘
  • 網(wǎng)站搭建搜外友鏈
  • 如何開網(wǎng)店無貨源不需要投資河北seo技術(shù)
  • 在設(shè)計賺錢的網(wǎng)站有哪些做網(wǎng)站需要多少錢
  • 廣東省農(nóng)業(yè)農(nóng)村廳官方網(wǎng)站成都網(wǎng)站快速開發(fā)
  • 建站源碼程序惠州seo外包服務(wù)
  • 自己的網(wǎng)站怎么開培訓(xùn)心得體會范文大全2000字
  • 外貿(mào)必看網(wǎng)站湖南百度seo
  • 做3d效果的網(wǎng)站亞馬遜關(guān)鍵詞排名提升
  • 松江品劃做網(wǎng)站云浮新增確診病例30例
  • 易企網(wǎng)站建設(shè)滁州網(wǎng)站seo
  • 系統(tǒng)優(yōu)化的方法知識點(diǎn)外貿(mào)建站優(yōu)化
  • 深圳網(wǎng)站建設(shè)加q479185700外貿(mào)網(wǎng)絡(luò)營銷推廣
  • 保障性租賃住房管理平臺優(yōu)化大師班級優(yōu)化大師
  • 網(wǎng)站建設(shè)與開發(fā)論文谷歌seo是什么意思
  • php外貿(mào)網(wǎng)站制作最快新聞資訊在哪看
  • 購物網(wǎng)站開發(fā)需求文檔百度云登錄入口
  • 石獅網(wǎng)站定制北京seo專業(yè)團(tuán)隊
  • #NAME?站長工具seo優(yōu)化系統(tǒng)
  • 網(wǎng)站描述是什么濟(jì)南網(wǎng)站seo優(yōu)化
  • 換接入商網(wǎng)站備案百度指數(shù)搜索
  • 安徽網(wǎng)站建站系統(tǒng)哪家好谷歌網(wǎng)站優(yōu)化推廣
  • 可以兼職做設(shè)計的網(wǎng)站百度收錄入口
  • 如何做網(wǎng)站價格策略seo職業(yè)培訓(xùn)班
  • 專業(yè)做俄語網(wǎng)站建設(shè)司排名第一的手機(jī)清理軟件
  • 婚紗攝影網(wǎng)站seo方案友情鏈接怎么做
  • 企業(yè)網(wǎng)站建設(shè)服務(wù)熱線搜狗搜索引擎網(wǎng)頁
  • 虛擬主機(jī)網(wǎng)站后臺友情鏈接購買
  • bitcoind 做交易網(wǎng)站windows永久禁止更新