ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## OAuth2认证 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。 ## 认证流程 ![](https://box.kancloud.cn/1389d9eec3d9b46b97af0e961fa2c4fe_1278x794.jpg) ## 主要代码 ### 依赖 ``` <dependency> <groupId>org.springframework.social</groupId> <artifactId>spring-social-security</artifactId> <version>${social.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-security</artifactId> </dependency> ``` ### 配置认证服务器 ~~~ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Autowired AuthenticationManager authenticationManager; @Autowired UserDetailsService userDetailsService; @Qualifier("dataSource") @Autowired DataSource dataSource; @Autowired TokenStore tokenStore; @Autowired(required = false) private JwtAccessTokenConverter jwtAccessTokenConverter; /** * 定义令牌端点 * @param endpoints * @throws Exception */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .authenticationManager(authenticationManager) .userDetailsService(userDetailsService) .tokenStore(tokenStore) .authorizationCodeServices(authorizationCodeServices()) .reuseRefreshTokens(false); // jwt支持 if (jwtAccessTokenConverter != null) { endpoints.accessTokenConverter(jwtAccessTokenConverter); } } /** * 定义令牌端点约束 * @param oauthServer * @throws Exception */ @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .allowFormAuthenticationForClients(); } /** * 客户端信息 * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { JdbcClientDetailsServiceBuilder builder = clients.jdbc(dataSource); } /** * 使用jdbc数据源的授权码 * @return */ @Bean protected AuthorizationCodeServices authorizationCodeServices() { return new JdbcAuthorizationCodeServices(dataSource); } } ~~~ ### 配置WebSecurityConfigurer ~~~ @Configuration @EnableWebSecurity @EnableConfigurationProperties(PermitUrlProperties.class) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private PermitUrlProperties permitUrlProperties; @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } SecurityProperties securityProperties = new SecurityProperties(); @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off http .formLogin().loginPage(FromLoginConstant.LOGIN_PAGE).loginProcessingUrl(FromLoginConstant.LOGIN_PROCESSING_URL) .and() .authorizeRequests().antMatchers( "/oauth/**", FromLoginConstant.LOGIN_PROCESSING_URL, FromLoginConstant.LOGIN_PAGE, securityProperties.getOauthLogin().getOauthLogin(), securityProperties.getOauthLogin().getOauthGrant()).permitAll().anyRequest().authenticated().and() .csrf().disable(); // @formatter:on } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers(permitUrlProperties.getIgnored()); } } ~~~ ### 配置tokenStore ~~~ @Slf4j @Configuration public class TokenStoreConfig { @Resource private DataSource dataSource; @Resource RedisProperties redisProperties; @Autowired(required = false) private RedisTemplate<String, Object> redisTemplate; @Bean @ConditionalOnProperty(prefix = "jfun", name = "tokenStoreType", havingValue = "jdbc") public JdbcTokenStore jdbcTokenStore() { log.info("-------------> 使用jdbc token"); return new JdbcTokenStore(dataSource); } @Bean @ConditionalOnProperty(prefix = "jfun", name = "tokenStoreType", havingValue = "redis") public RedisTokenStore redisStore(RedisConnectionFactory redisConnectionFactory) { //redis 集群 log.info("-------------> 使用redis token"); RedisTokenStore redisTemplateStore = new RedisTokenStore(redisConnectionFactory); return redisTemplateStore; } @Configuration @ConditionalOnProperty(prefix = "jfun", name = "type", havingValue = "tokenStoreType") public static class JwtTokenConfig { @Bean public JwtTokenStore jwtTokenStore() { log.info("-------------> 使用jwt token"); return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { // keytool -genkeypair -alias jfuncloud -keyalg RSA -keypass jfuncloud -keystore jfuncloud.jks -storepass jfuncloud // keytool -list -rfc --keystore jfuncloud.jks | openssl x509 -inform pem -pubkey //使用非对称加密 JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jfuncloud.jks"), "jfuncloud".toCharArray()); converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jfuncloud")); converter.setAccessTokenConverter(new ResJwtAccessTokenConverter()); return converter; } } } ~~~