Skip to content

Commit 90be6e8

Browse files
committed
Rate limit login
1 parent 1ee5e54 commit 90be6e8

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

knowledge-manager-ui/src/app/components/login/login.component.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,23 @@ export class LoginComponent {
5050
},
5151
error: (err) => {
5252
console.error('Login failed:', err);
53-
this.snackBar.open(
54-
'Login fehlgeschlagen. Bitte stellen Sie sicher, dass Ihre E-Mail-Adresse bestätigt ist, Ihr Passwort korrekt ist und Ihr Konto von einem Administrator freigegeben wurde.',
55-
'Schließen', {
56-
duration: 4000,
57-
horizontalPosition: 'right',
58-
verticalPosition: 'top',
59-
panelClass: ['error-snack-bar'],
53+
if (err?.status === 429) {
54+
this.snackBar.open(
55+
'Zu viele Login-Versuche. Bitte versuchen Sie es später erneut.',
56+
'Schließen',
57+
{ duration: 4000, horizontalPosition: 'right', verticalPosition: 'top', panelClass: ['error-snack-bar'] }
58+
);
59+
} else {
60+
this.snackBar.open(
61+
'Login fehlgeschlagen. Bitte stellen Sie sicher, dass Ihre E-Mail-Adresse bestätigt ist, Ihr Passwort korrekt ist und Ihr Konto von einem Administrator freigegeben wurde.',
62+
'Schließen', {
63+
duration: 4000,
64+
horizontalPosition: 'right',
65+
verticalPosition: 'top',
66+
panelClass: ['error-snack-bar'],
67+
}
68+
);
6069
}
61-
);
6270
}
6371
});
6472
}

reverse-proxy/nginx.conf

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ lua_shared_dict mail_limit 10m;
88
# Per-user chat limit: 15 requests per day
99
lua_shared_dict chat_limit 10m;
1010

11+
# Global daily cap for login attempts
12+
lua_shared_dict login_global 1m;
13+
14+
# Tiny token-bucket just to smooth bursts
15+
lua_shared_dict login_bucket 1m;
16+
1117
server {
1218
listen 80;
1319
listen [::]:80;
@@ -175,4 +181,48 @@ server {
175181
proxy_set_header X-Internal-Access "true";
176182
proxy_set_header Origin $http_origin;
177183
}
184+
185+
location = /api/users/login {
186+
access_by_lua_block {
187+
local gdict = ngx.shared.login_global
188+
local gkey = "global"
189+
local gcount = gdict:get(gkey) or 0
190+
if gcount >= 40 then
191+
ngx.log(ngx.ERR, "Global login limit reached")
192+
return ngx.exit(429)
193+
end
194+
local ngc, err = gdict:incr(gkey, 1)
195+
if not ngc then
196+
gdict:set(gkey, 1, 86400)
197+
end
198+
199+
local limit = require "resty.limit.req"
200+
local lim, err = limit.new("login_bucket", 5/60, 10)
201+
if not lim then
202+
ngx.log(ngx.ERR, "login bucket init failed: ", err)
203+
return ngx.exit(500)
204+
end
205+
206+
local delay, err = lim:incoming("bucket", true)
207+
if not delay then
208+
if err == "rejected" then
209+
return ngx.exit(429)
210+
end
211+
ngx.log(ngx.ERR, "login bucket error: ", err)
212+
return ngx.exit(500)
213+
end
214+
215+
if delay >= 0.001 then
216+
ngx.sleep(delay)
217+
end
218+
}
219+
220+
proxy_pass http://angelos-server:9007;
221+
proxy_set_header Host $host;
222+
proxy_set_header X-Real-IP $remote_addr;
223+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
224+
proxy_set_header X-Forwarded-Proto $scheme;
225+
proxy_set_header X-Internal-Access "true";
226+
proxy_set_header Origin $http_origin;
227+
}
178228
}

0 commit comments

Comments
 (0)