面试题答案
一键面试令牌生成
- 使用安全随机数生成算法:
- 例如在Java中可以使用
SecureRandom
类来生成随机数,作为令牌的基础部分。如:
SecureRandom random = new SecureRandom(); byte[] tokenBytes = new byte[32]; random.nextBytes(tokenBytes); String token = Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);
- 在Python中可以使用
os.urandom
来生成随机字节串,然后进行编码:
import os import base64 token_bytes = os.urandom(32) token = base64.urlsafe_b64encode(token_bytes).decode('utf - 8').rstrip('=')
- 例如在Java中可以使用
- 加入时间戳或唯一标识符:为了增加令牌的唯一性和可追溯性,可以在令牌中加入时间戳或与客户端相关的唯一标识符。例如,将当前时间的毫秒数与随机数组合,然后进行哈希运算得到最终令牌。
令牌加密
- 对称加密:
- 可以使用AES(高级加密标准)算法。在Java中,使用
javax.crypto
包来实现AES加密。例如:
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec iv = new IvParameterSpec(ivBytes); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); byte[] encryptedToken = cipher.doFinal(token.getBytes());
- 在Python中,可以使用
pycryptodome
库:
from Crypto.Cipher import AES from Crypto.Util.Padding import pad cipher = AES.new(key, AES.MODE_CBC, iv) encrypted_token = cipher.encrypt(pad(token.encode('utf - 8'), AES.block_size))
- 可以使用AES(高级加密标准)算法。在Java中,使用
- 非对称加密:
- 使用RSA算法,在Java中,通过
java.security
包实现。例如:
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(2048); KeyPair keyPair = keyPairGen.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedToken = cipher.doFinal(token.getBytes());
- 在Python中,使用
cryptography
库:
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import serialization, hashes private_key = rsa.generate_private_key( public_exponent = 65537, key_size = 2048, backend = default_backend() ) public_key = private_key.public_key() encrypted_token = public_key.encrypt( token.encode('utf - 8'), padding.OAEP( mgf = padding.MGF1(algorithm = hashes.SHA256()), algorithm = hashes.SHA256(), label = None ) )
- 使用RSA算法,在Java中,通过
有效期设置
- 短期令牌:设置较短的有效期,例如15分钟到1小时。这样可以减少令牌泄露带来的风险。可以在生成令牌时记录生成时间,当客户端使用令牌时,检查当前时间与生成时间的差值是否超过有效期。
- 刷新令牌:颁发一个长期有效的刷新令牌,用于在短期令牌过期时获取新的短期令牌。刷新令牌也应设置有效期,但可以相对较长,如7天到30天。当短期令牌过期时,客户端使用刷新令牌向授权服务器请求新的短期令牌。
高并发场景下保证一致性和安全性
- 分布式缓存:
- 使用如Redis这样的分布式缓存来存储令牌。Redis具有高并发处理能力,并且支持原子操作。可以将令牌作为键,相关的用户信息或客户端信息作为值存储在Redis中。例如,在Java中使用Jedis库:
Jedis jedis = new Jedis("localhost"); jedis.setex(token, expirationSeconds, userInfoJson);
- 在Python中使用
redis - py
库:
import redis r = redis.Redis(host='localhost', port = 6379, db = 0) r.setex(token, expiration_seconds, user_info_json)
- 数据库事务:如果使用数据库存储令牌,利用数据库的事务机制来保证在高并发下令牌操作的一致性。例如在MySQL中,使用
START TRANSACTION
、COMMIT
和ROLLBACK
语句来确保令牌的生成、存储和验证操作要么全部成功,要么全部失败。 - 负载均衡与集群:部署多个授权服务器实例,并使用负载均衡器(如Nginx)将请求均匀分配到各个实例上。同时,这些实例可以共享分布式缓存(如Redis集群),以确保令牌数据的一致性。
- 令牌验证频率:在高并发场景下,为了减少验证令牌带来的性能开销,可以在客户端缓存令牌验证结果,并设置一个较短的缓存有效期。当验证请求到达时,先检查本地缓存,如果缓存中有验证结果且未过期,则直接返回,否则再向授权服务器验证。