#
Junjie
昨天 bd6b518aae61608ddc2d82b43ccc283dc95b9c54
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.zy.common.auth;
 
import com.core.common.Cools;
import org.springframework.stereotype.Component;
 
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
@Component
public class MfaLoginTicketManager {
 
    private static final long EXPIRE_MILLIS = 5 * 60 * 1000L;
 
    private final SecureRandom secureRandom = new SecureRandom();
    private final ConcurrentHashMap<String, TicketHolder> holders = new ConcurrentHashMap<>();
 
    public String create(Long userId) {
        cleanup();
        String ticket;
        do {
            ticket = randomTicket();
        } while (holders.putIfAbsent(ticket, new TicketHolder(userId, System.currentTimeMillis() + EXPIRE_MILLIS)) != null);
        return ticket;
    }
 
    public Long getUserId(String ticket) {
        if (Cools.isEmpty(ticket)) {
            return null;
        }
        TicketHolder holder = holders.get(ticket);
        if (holder == null) {
            return null;
        }
        if (holder.expireAt < System.currentTimeMillis()) {
            holders.remove(ticket);
            return null;
        }
        return holder.userId;
    }
 
    public void remove(String ticket) {
        if (!Cools.isEmpty(ticket)) {
            holders.remove(ticket);
        }
    }
 
    private void cleanup() {
        long now = System.currentTimeMillis();
        for (Map.Entry<String, TicketHolder> entry : holders.entrySet()) {
            if (entry.getValue().expireAt < now) {
                holders.remove(entry.getKey());
            }
        }
    }
 
    private String randomTicket() {
        byte[] bytes = new byte[24];
        secureRandom.nextBytes(bytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }
 
    private static final class TicketHolder {
        private final Long userId;
        private final long expireAt;
 
        private TicketHolder(Long userId, long expireAt) {
            this.userId = userId;
            this.expireAt = expireAt;
        }
    }
}