最近在学习Spring cloud微服务的搭建,采用Spring 的 OAuth2作为单点登录服务器,通过zuul作统一路由,所以认证服务 (Authentication Server)端可通过多实例进行集群部署,集群部署时需要对认证服务 (Authentication Server)进行如下几点配置。
1、通过redis存储AccessToken
@Configuration public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private RedisConnectionFactory redisConnectionFactory; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager).accessTokenConverter(jwtAccessTokenConverter()); endpoints.tokenStore(tokenStore()); } @Bean public TokenStore tokenStore() { return new RedisTokenStore(redisConnectionFactory); } }
2、共享Authentication code
目前spring提供了内存和数据库两种方式存储授权码Authentication code,要实现多个实例之间共享可以选在将AuthenTicationCode存储在数据中,相关配置为
@Bean public AuthorizationCodeServices authorizationCodeServices(){ return new JdbcAuthorizationCodeServices(dataSource); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager).accessTokenConverter(jwtAccessTokenConverter()); endpoints.tokenStore(tokenStore()); endpoints.authorizationCodeServices(authorizationCodeServices()); }
需要在数据库中创建表 auth_code
CREATE TABLE `oauth_code` ( `code` varchar(1024) DEFAULT NULL, `authentication` blob )
我们也可以自定义AuthorizationCodeServices实现类来将auth_code 存放在redis中
public class RedisAuthenticationCodeServices extends RandomValueAuthorizationCodeServices { private static Logger log = Logger.getLogger(RedisAuthenticationCodeServices.class); private static final String AUTH_CODE_KEY = "auth_code"; private RedisConnectionFactory connectionFactory; public RedisAuthenticationCodeServices(RedisConnectionFactory connectionFactory) { Assert.notNull(connectionFactory, "RedisConnectionFactory required"); this.connectionFactory = connectionFactory; } @Override protected OAuth2Authentication remove(String code) { RedisConnection conn = getConnection(); try { OAuth2Authentication authentication = null; try { authentication = SerializationUtils .deserialize(conn.hGet(AUTH_CODE_KEY.getBytes("utf-8"), code.getBytes("utf-8"))); } catch (Exception e) { return null; } if (null != authentication) { conn.hDel(AUTH_CODE_KEY.getBytes("utf-8"), code.getBytes("utf-8")); } return authentication; } catch (Exception e) { return null; } finally { conn.close(); } } @Override protected void store(String code, OAuth2Authentication authentication) { RedisConnection conn = getConnection(); try { conn.hSet(AUTH_CODE_KEY.getBytes("utf-8"), code.getBytes("utf-8"), SerializationUtils.serialize(authentication)); } catch (Exception e) { log.error("保存authentication code 失败", e); } finally { conn.close(); } } private RedisConnection getConnection() { return connectionFactory.getConnection(); } }
3、共享session
OAuth2服务在申请授权码时会先判断用户是否登录,如未登录则会引导到登录页面,所以我们需要在不同实例之间共享session,我么可以通过Spring的Session很容易的实现session共享。首先引入jar包,maven的配置如下
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> </dependency>
通过@EnableRedisHttpSession注解开启session共享。