diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/DemoSocialConfigure.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/DemoSocialConfigure.java new file mode 100644 index 000000000..6e0a930a9 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/DemoSocialConfigure.java @@ -0,0 +1,32 @@ +package com.xkcoding.social.config; + +import org.springframework.social.security.SocialAuthenticationFilter; +import org.springframework.social.security.SpringSocialConfigurer; + +/** + *
+ * 继承默认的社交登录配置,加入自定义的后处理逻辑 + *
+ * + * @package: com.xkcoding.social.config + * @description: 继承默认的社交登录配置,加入自定义的后处理逻辑 + * @author: yangkai.shen + * @date: Created in 2019-02-21 14:01 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class DemoSocialConfigure extends SpringSocialConfigurer { + private String filterProcessUrl; + + public DemoSocialConfigure(String filterProcessUrl) { + this.filterProcessUrl = filterProcessUrl; + } + + @Override + protected+ * 根据userId获取用户信息 + *
+ * + * @package: com.xkcoding.social.config + * @description: 根据userId获取用户信息 + * @author: yangkai.shen + * @date: Created in 2019-02-21 14:41 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Service +public class DemoUserDetailService implements SocialUserDetailsService { + @Autowired + private PasswordEncoder passwordEncoder; + + @Override + public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException { + return new SocialUser(userId, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("xxx")); + } +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/QQProperties.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/QQProperties.java new file mode 100644 index 000000000..e04e7f333 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/QQProperties.java @@ -0,0 +1,34 @@ +package com.xkcoding.social.config; + +import lombok.Data; + +/** + *+ * QQ 配置 + *
+ * + * @package: com.xkcoding.social.config + * @description: QQ 配置 + * @author: yangkai.shen + * @date: Created in 2019-02-21 14:20 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class QQProperties { + /** + * 第三方应用标识 + */ + private String providerId = "qq"; + + /** + * clientId + */ + private String clientId; + + /** + * clientSecret + */ + private String clientSecret; +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/SocialConfig.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/SocialConfig.java new file mode 100644 index 000000000..ec639c471 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/SocialConfig.java @@ -0,0 +1,67 @@ +package com.xkcoding.social.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.encrypt.Encryptors; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.social.UserIdSource; +import org.springframework.social.config.annotation.EnableSocial; +import org.springframework.social.config.annotation.SocialConfigurerAdapter; +import org.springframework.social.connect.ConnectionFactoryLocator; +import org.springframework.social.connect.UsersConnectionRepository; +import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository; +import org.springframework.social.security.AuthenticationNameUserIdSource; +import org.springframework.social.security.SpringSocialConfigurer; + +import javax.sql.DataSource; + +/** + *+ * 社交登录配置 + *
+ * + * @package: com.xkcoding.social.config + * @description: 社交登录配置 + * @author: yangkai.shen + * @date: Created in 2019-02-21 13:52 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +@EnableSocial +@EnableConfigurationProperties({SocialProperties.class}) +public class SocialConfig extends SocialConfigurerAdapter { + @Autowired + private DataSource dataSource; + + @Autowired + private SocialProperties socialProperties; + + @Override + public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) { + JdbcUsersConnectionRepository jdbcUsersConnectionRepository = new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors + .noOpText()); + jdbcUsersConnectionRepository.setTablePrefix("demo_"); + return jdbcUsersConnectionRepository; + } + + @Bean + public SpringSocialConfigurer springSocialConfigurer() { + DemoSocialConfigure demoSocialConfigure = new DemoSocialConfigure(socialProperties.getFilterProcessUrl()); + return demoSocialConfigure; + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + public UserIdSource getUserIdSource() { + return new AuthenticationNameUserIdSource(); + } +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/SocialProperties.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/SocialProperties.java new file mode 100644 index 000000000..9f8686d67 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/config/SocialProperties.java @@ -0,0 +1,25 @@ +package com.xkcoding.social.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + *+ * 社交登录配置类 + *
+ * + * @package: com.xkcoding.social.config + * @description: 社交登录配置类 + * @author: yangkai.shen + * @date: Created in 2019-02-21 14:12 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +@ConfigurationProperties(prefix = "demo.social") +public class SocialProperties { + private String filterProcessUrl = "/auth"; + + private QQProperties qq = new QQProperties(); +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/QQ.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/QQ.java new file mode 100644 index 000000000..c9a65a6f3 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/QQ.java @@ -0,0 +1,24 @@ +package com.xkcoding.social.qq.api; + +/** + *+ * 获取QQ用户信息接口 + *
+ * + * @package: com.xkcoding.social.qq.api + * @description: 获取QQ用户信息接口 + * @author: yangkai.shen + * @date: Created in 2019-02-21 10:52 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +public interface QQ { + + /** + * 获取QQ用户信息 + * @return QQ用户信息 + */ + QQUserInfo getUserInfo(); + +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/QQUserInfo.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/QQUserInfo.java new file mode 100644 index 000000000..5e25f1577 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/QQUserInfo.java @@ -0,0 +1,82 @@ +package com.xkcoding.social.qq.api; + +import lombok.Data; + +/** + *+ * QQ用户信息 + *
+ * + * @package: com.xkcoding.social.qq.api + * @description: QQ用户信息 + * @author: yangkai.shen + * @date: Created in 2019-02-21 10:52 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class QQUserInfo { + /** + * QQ唯一标识 + */ + private String openId; + /** + * 返回码 + */ + private String ret; + /** + * 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。 + */ + private String msg; + /** + * 用户在QQ空间的昵称。 + */ + private String nickname; + /** + * 大小为30×30像素的QQ空间头像URL。 + */ + private String figureurl; + /** + * 大小为50×50像素的QQ空间头像URL。 + */ + private String figureurl_1; + /** + * 大小为100×100像素的QQ空间头像URL。 + */ + private String figureurl_2; + /** + * 大小为40×40像素的QQ头像URL。 + */ + private String figureurl_qq_1; + /** + * 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有。 + */ + private String figureurl_qq_2; + /** + * 性别。 如果获取不到则默认返回"男" + */ + private String gender; + /** + * 是否黄钻 + */ + private String is_yellow_vip; + /** + * 是否会员 + */ + private String vip; + /** + * 黄钻等级 + */ + private String yellow_vip_level; + /** + * 会员等级 + */ + private String level; + /** + * 是否年费黄钻 + */ + private String is_yellow_year_vip; + + +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/impl/QQImpl.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/impl/QQImpl.java new file mode 100644 index 000000000..8b6bf7f02 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/api/impl/QQImpl.java @@ -0,0 +1,78 @@ +package com.xkcoding.social.qq.api.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.xkcoding.social.qq.api.QQ; +import com.xkcoding.social.qq.api.QQUserInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.social.oauth2.AbstractOAuth2ApiBinding; +import org.springframework.social.oauth2.TokenStrategy; +import org.springframework.util.MultiValueMap; + +/** + *+ * 获取QQ用户信息接口实现 + *
+ * + * @package: com.xkcoding.social.qq.api.impl + * @description: 获取QQ用户信息接口实现 + * @author: yangkai.shen + * @date: Created in 2019-02-21 10:57 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Slf4j +public class QQImpl extends AbstractOAuth2ApiBinding implements QQ { + + private String clientId; + + private String openId; + + /** + * 获取 openId,文档:http://wiki.connect.qq.com/%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7openid_oauth2-0 + */ + private static final String URL_FOR_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s"; + + /** + * 获取用户信息 URL,文档:http://wiki.connect.qq.com/get_user_info + */ + private static final String URL_FOR_USER_INFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%sopenid=%s"; + + /** + * {@link TokenStrategy#ACCESS_TOKEN_PARAMETER} 将 token 封装为参数传递,key为 access_token+ * QQ社交登录自动装配类 + *
+ * + * @package: com.xkcoding.social.qq.config + * @description: QQ社交登录自动装配类 + * @author: yangkai.shen + * @date: Created in 2019-02-21 14:08 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +@ConditionalOnProperty(prefix = "demo.social.qq", name = "clientId") +public class QQAutoConfig extends SocialConfigurerAdapter { + @Autowired + private SocialProperties socialProperties; + + @Override + public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) { + QQProperties qq = socialProperties.getQq(); + QQConnectionFactory qqConnectionFactory = new QQConnectionFactory(qq.getProviderId(), qq.getClientId(), qq.getClientSecret()); + connectionFactoryConfigurer.addConnectionFactory(qqConnectionFactory); + super.addConnectionFactories(connectionFactoryConfigurer, environment); + } +} diff --git a/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/connect/QQAdapter.java b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/connect/QQAdapter.java new file mode 100644 index 000000000..7fb4e6871 --- /dev/null +++ b/spring-boot-demo-social/src/main/java/com/xkcoding/social/qq/connect/QQAdapter.java @@ -0,0 +1,59 @@ +package com.xkcoding.social.qq.connect; + +import com.xkcoding.social.qq.api.QQ; +import com.xkcoding.social.qq.api.QQUserInfo; +import org.springframework.social.connect.ApiAdapter; +import org.springframework.social.connect.ConnectionValues; +import org.springframework.social.connect.UserProfile; + +/** + *+ * QQ 用户适配器 + *
+ * + * @package: com.xkcoding.social.qq.connect + * @description: QQ 用户适配器 + * @author: yangkai.shen + * @date: Created in 2019-02-21 13:46 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class QQAdapter implements ApiAdapter+ * QQ 连接工厂 + *
+ * + * @package: com.xkcoding.social.qq.connect + * @description: QQ 连接工厂 + * @author: yangkai.shen + * @date: Created in 2019-02-21 13:50 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class QQConnectionFactory extends OAuth2ConnectionFactory+ * ①获取授权码code ②根据code换取令牌accessToken + *
+ * + * @package: com.xkcoding.social.qq.connect + * @description: ①获取授权码code ②根据code换取令牌accessToken + * @author: yangkai.shen + * @date: Created in 2019-02-21 11:22 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Slf4j +public class QQOauth2Template extends OAuth2Template { + + public QQOauth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) { + super(clientId, clientSecret, authorizeUrl, accessTokenUrl); + + // 默认不携带 client_id 和 client_secret,根据文档需要携带这两个参数 + setUseParametersForClientAuthentication(true); + } + + /** + * 根据code换取access_token,父类默认处理的是json格式,但是根据QQ文档,格式不是json格式,需要我们重写,自行处理 + * + * @param accessTokenUrl 换取 access_token 的 URL 地址 + * @param parameters 参数 + * @return {@link AccessGrant} + */ + @Override + protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap+ * 定义获取授权码地址和获取令牌地址,同时定义QQImpl + *
+ * + * @package: com.xkcoding.social.qq.connect + * @description: 定义获取授权码地址和获取令牌地址,同时定义QQImpl + * @author: yangkai.shen + * @date: Created in 2019-02-21 13:28 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class QQServiceProvider extends AbstractOAuth2ServiceProvider