mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 03:53:09 +00:00
loginserver and example
This commit is contained in:
8
examples/config.login
Normal file
8
examples/config.login
Normal file
@@ -0,0 +1,8 @@
|
||||
thread = 8
|
||||
logger = nil
|
||||
harbor = 0
|
||||
start = "main"
|
||||
bootstrap = "snlua bootstrap" -- The service for bootstrap
|
||||
luaservice = "./service/?.lua;./examples/login/?.lua"
|
||||
lualoader = "lualib/loader.lua"
|
||||
cpath = "./cservice/?.so"
|
||||
59
examples/login/client.lua
Normal file
59
examples/login/client.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
package.cpath = "luaclib/?.so"
|
||||
|
||||
local socket = require "clientsocket"
|
||||
local cjson = require "cjson"
|
||||
local crypt = require "crypt"
|
||||
|
||||
local last
|
||||
local fd = assert(socket.connect("127.0.0.1", 8001))
|
||||
local input = {}
|
||||
|
||||
local function readline()
|
||||
local line = table.remove(input, 1)
|
||||
if line then
|
||||
return line
|
||||
end
|
||||
|
||||
while true do
|
||||
local status
|
||||
status, last = socket.readline(fd, last, input)
|
||||
if status == nil then
|
||||
error "Server closed"
|
||||
end
|
||||
if not status then
|
||||
socket.usleep(100)
|
||||
else
|
||||
local line = table.remove(input, 1)
|
||||
if line then
|
||||
return line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local challenge = crypt.base64decode(readline())
|
||||
|
||||
local clientkey = crypt.randomkey()
|
||||
socket.writeline(fd, crypt.base64encode(crypt.dhexchange(clientkey)))
|
||||
local secret = crypt.dhsecret(crypt.base64decode(readline()), clientkey)
|
||||
|
||||
print("sceret is ", crypt.hexencode(secret))
|
||||
|
||||
local hmac = crypt.hmac64(challenge, secret)
|
||||
socket.writeline(fd, crypt.base64encode(hmac))
|
||||
|
||||
local token = {
|
||||
user = "hello",
|
||||
pass = "password",
|
||||
}
|
||||
|
||||
local etoken = crypt.desencode(secret, cjson.encode(token))
|
||||
local b = crypt.base64encode(etoken)
|
||||
socket.writeline(fd, crypt.base64encode(etoken))
|
||||
|
||||
print(readline())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
examples/login/logind.lua
Normal file
25
examples/login/logind.lua
Normal file
@@ -0,0 +1,25 @@
|
||||
local login = require "loginserver"
|
||||
local json = require "cjson"
|
||||
local crypt = require "crypt"
|
||||
|
||||
local server = {
|
||||
host = "127.0.0.1",
|
||||
port = 8001,
|
||||
}
|
||||
|
||||
function server.auth_handler(token)
|
||||
token = json.decode(token)
|
||||
assert(token.user)
|
||||
assert(token.pass == "password")
|
||||
return "sample", token.user
|
||||
end
|
||||
|
||||
function server.login_handler(server, uid, secret)
|
||||
print(string.format("%s@%s is login, secret is %s", uid, server, crypt.hexencode(secret)))
|
||||
end
|
||||
|
||||
function server.logout_handler(server, uid)
|
||||
print(string.format("%s@%s is logout", uid, server))
|
||||
end
|
||||
|
||||
login(server)
|
||||
5
examples/login/main.lua
Normal file
5
examples/login/main.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
local skynet = require "skynet"
|
||||
|
||||
skynet.start(function()
|
||||
skynet.newservice "logind"
|
||||
end)
|
||||
133
lualib/loginserver.lua
Normal file
133
lualib/loginserver.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local skynet = require "skynet"
|
||||
local socket = require "socket"
|
||||
local crypt = require "crypt"
|
||||
local datacenter = require "datacenter"
|
||||
|
||||
local function launch_slave(auth_handler)
|
||||
local cmd = {}
|
||||
|
||||
-- set socket buffer limit (8K)
|
||||
-- If the attacker send large package, close the socket
|
||||
socket.limit(8192)
|
||||
|
||||
function cmd.auth(fd, addr)
|
||||
skynet.error(string.format("connect from %s (fd = %d)", addr, fd))
|
||||
socket.start(fd)
|
||||
local challenge = crypt.randomkey()
|
||||
socket.write(fd, crypt.base64encode(challenge).."\n")
|
||||
|
||||
local handshake = assert(socket.readline(fd), "socket closed")
|
||||
local clientkey = crypt.base64decode(handshake)
|
||||
if #clientkey ~= 8 then
|
||||
error "Invalid client key"
|
||||
end
|
||||
local serverkey = crypt.randomkey()
|
||||
socket.write(fd, crypt.base64encode(crypt.dhexchange(serverkey)).."\n")
|
||||
|
||||
local secret = crypt.dhsecret(clientkey, serverkey)
|
||||
|
||||
local response = assert(socket.readline(fd), "socket closed")
|
||||
local hmac = crypt.hmac64(challenge, secret)
|
||||
|
||||
if hmac ~= crypt.base64decode(response) then
|
||||
socket.write(fd, "400 Bad Request\n")
|
||||
error "challenge failed"
|
||||
end
|
||||
|
||||
local etoken = assert(socket.readline(fd), "socket closed")
|
||||
|
||||
local token = crypt.desdecode(secret, crypt.base64decode(etoken))
|
||||
|
||||
local ok, server, uid = pcall(auth_handler,token)
|
||||
|
||||
socket.abandon(fd)
|
||||
return ok, server, uid, secret
|
||||
end
|
||||
|
||||
skynet.dispatch("lua", function(_,_,command,...)
|
||||
local f = assert(cmd[command])
|
||||
skynet.ret(skynet.pack(f(...)))
|
||||
end)
|
||||
end
|
||||
|
||||
local function accept(conf, s, fd, addr)
|
||||
local ok, server, uid, secret = skynet.call(s, "lua", "auth", fd, addr)
|
||||
if not ok then
|
||||
socket.write(fd, "401 Unauthorized\n")
|
||||
error(server)
|
||||
end
|
||||
|
||||
socket.start(fd)
|
||||
|
||||
local ok, err = pcall(conf.login_handler, server, uid, secret)
|
||||
if ok then
|
||||
socket.write(fd, "200 OK\n")
|
||||
else
|
||||
socket.write(fd, "406 Not Acceptable\n")
|
||||
error(err)
|
||||
end
|
||||
end
|
||||
|
||||
local function launch_master(conf)
|
||||
local instance = conf.instance or 8
|
||||
assert(instance > 0)
|
||||
local host = conf.host or "0.0.0.0"
|
||||
local port = assert(tonumber(conf.port))
|
||||
local slave = {}
|
||||
local balance = 1
|
||||
local cmd = {}
|
||||
|
||||
function cmd.logout(server, uid)
|
||||
conf.logout_handler(server, uid)
|
||||
end
|
||||
|
||||
if conf.init then
|
||||
conf.init()
|
||||
conf.init = nil
|
||||
end
|
||||
|
||||
for i=1,instance do
|
||||
slave[i] = skynet.newservice(SERVICE_NAME)
|
||||
end
|
||||
|
||||
skynet.dispatch("lua", function(_,_,command, ...)
|
||||
local f = assert(cmd[command])
|
||||
skynet.ret(skynet.pack(f(...)))
|
||||
end)
|
||||
|
||||
local id = socket.listen(host, port)
|
||||
skynet.error(string.format("login server listen at : %s %d", host, port))
|
||||
socket.start(id , function(fd, addr)
|
||||
local s = slave[balance]
|
||||
balance = balance + 1
|
||||
if balance > instance then
|
||||
balance = 1
|
||||
end
|
||||
local ok, err = pcall(accept, conf, s, fd, addr)
|
||||
if not ok then
|
||||
skynet.error(string.format("invalid client (fd = %d) error = %s", fd, err))
|
||||
end
|
||||
socket.close(fd)
|
||||
end)
|
||||
end
|
||||
|
||||
local function login (conf)
|
||||
skynet.start(function()
|
||||
local loginmaster = datacenter.get "login_master"
|
||||
if loginmaster then
|
||||
local auth_handler = assert(conf.auth_handler)
|
||||
launch_master = nil
|
||||
conf = nil
|
||||
launch_slave(auth_handler)
|
||||
else
|
||||
launch_slave = nil
|
||||
conf.auth_handler = nil
|
||||
assert(conf.login_handler)
|
||||
assert(conf.logout_handler)
|
||||
datacenter.set("login_master", skynet.self())
|
||||
launch_master(conf)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return login
|
||||
Reference in New Issue
Block a user