面试题答案
一键面试1. 缓存机制优化
在认证与授权流程中,很多信息是重复使用的,比如用户的权限信息等。可以使用缓存来存储这些信息,避免每次都从数据库或其他持久化存储中查询。
- 使用Guava Cache:
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
public class AuthCache {
private static final Cache<String, Object> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.build();
public static void put(String key, Object value) {
cache.put(key, value);
}
public static Object get(String key) {
return cache.getIfPresent(key);
}
}
在认证授权方法中,可以先从缓存中获取用户权限等信息:
public boolean hasPermission(String userId, String permission) {
String cacheKey = userId + ":" + permission;
Object result = AuthCache.get(cacheKey);
if (result != null) {
return (boolean) result;
}
// 如果缓存中没有,查询数据库等持久化存储
boolean hasPermission = queryFromDB(userId, permission);
AuthCache.put(cacheKey, hasPermission);
return hasPermission;
}
- 使用Redis缓存:
import redis.clients.jedis.Jedis;
public class RedisAuthCache {
private static final Jedis jedis = new Jedis("localhost", 6379);
public static void put(String key, String value) {
jedis.set(key, value);
}
public static String get(String key) {
return jedis.get(key);
}
}
类似地,在认证授权逻辑中:
public boolean hasPermission(String userId, String permission) {
String cacheKey = userId + ":" + permission;
String result = RedisAuthCache.get(cacheKey);
if (result != null) {
return Boolean.parseBoolean(result);
}
boolean hasPermission = queryFromDB(userId, permission);
RedisAuthCache.put(cacheKey, String.valueOf(hasPermission));
return hasPermission;
}
2. 分布式认证服务
在高并发场景下,单点的认证服务可能成为性能瓶颈。可以采用分布式认证服务,例如使用OAuth 2.0的一些框架(如Spring Security OAuth2)搭建分布式认证中心。
- Spring Security OAuth2 分布式认证示例: 在认证服务器配置类中:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientId")
.secret("{noop}secret")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.redirectUris("http://localhost:8080/login");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore());
}
private TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
// 省略JwtAccessTokenConverter等配置
}
资源服务器配置类:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll();
}
}
通过这种方式,不同的服务可以通过统一的认证中心进行认证和授权,减轻单个服务的认证压力。
3. 权限预加载
在系统启动时,将常用的权限信息预加载到内存中,避免在运行时频繁查询数据库。
- 基于Spring的权限预加载:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class PermissionPreloader implements CommandLineRunner {
@Autowired
private PermissionService permissionService;
@Override
public void run(String... args) throws Exception {
List<String> allPermissions = permissionService.getAllPermissions();
// 这里可以将allPermissions存储到缓存或者全局变量中
// 例如 AuthCache.put("allPermissions", allPermissions);
}
}
在权限校验方法中:
public boolean hasPermission(String userId, String permission) {
// 从预加载的权限信息中获取用户权限
List<String> allPermissions = (List<String>) AuthCache.get("allPermissions");
if (allPermissions != null) {
// 这里简单示例,实际可能需要更复杂的逻辑
return allPermissions.contains(permission);
}
// 如果预加载信息没有,再查询数据库
return queryFromDB(userId, permission);
}
通过以上缓存机制、分布式认证服务和权限预加载等优化措施,可以有效减少认证与授权流程中的资源消耗和响应延迟,提升高并发企业级Java应用的性能。