博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用SpringSocial开发QQ登录
阅读量:5035 次
发布时间:2019-06-12

本文共 20349 字,大约阅读时间需要 67 分钟。

⒈编写QQ用户对应的数据结构

1 package cn.coreqi.social.qq.entities;  2   3 /**  4  * 封装QQ的用户信息  5  */  6 public class QQUserInfo {  7   8     /**  9      * 返回码 10      */ 11     private String ret; 12     /** 13      * 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。 14      */ 15     private String msg; 16     /** 17      * 18      */ 19     private String openId; 20     /** 21      * 不知道什么东西,文档上没写,但是实际api返回里有。 22      */ 23     private String is_lost; 24     /** 25      * 省(直辖市) 26      */ 27     private String province; 28     /** 29      * 市(直辖市区) 30      */ 31     private String city; 32     /** 33      * 出生年月 34      */ 35     private String year; 36     /** 37      * 用户在QQ空间的昵称。 38      */ 39     private String nickname; 40     /** 41      * 大小为30×30像素的QQ空间头像URL。 42      */ 43     private String figureurl; 44     /** 45      * 大小为50×50像素的QQ空间头像URL。 46      */ 47     private String figureurl_1; 48     /** 49      * 大小为100×100像素的QQ空间头像URL。 50      */ 51     private String figureurl_2; 52     /** 53      * 大小为40×40像素的QQ头像URL。 54      */ 55     private String figureurl_qq_1; 56     /** 57      * 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100×100的头像,但40×40像素则是一定会有。 58      */ 59     private String figureurl_qq_2; 60     /** 61      * 性别。 如果获取不到则默认返回”男” 62      */ 63     private String gender; 64     /** 65      * 标识用户是否为黄钻用户(0:不是;1:是)。 66      */ 67     private String is_yellow_vip; 68     /** 69      * 标识用户是否为黄钻用户(0:不是;1:是) 70      */ 71     private String vip; 72     /** 73      * 黄钻等级 74      */ 75     private String yellow_vip_level; 76     /** 77      * 黄钻等级 78      */ 79     private String level; 80     /** 81      * 标识是否为年费黄钻用户(0:不是; 1:是) 82      */ 83     private String is_yellow_year_vip; 84  85  86     public String getRet() { 87         return ret; 88     } 89  90     public void setRet(String ret) { 91         this.ret = ret; 92     } 93  94     public String getMsg() { 95         return msg; 96     } 97  98     public void setMsg(String msg) { 99         this.msg = msg;100     }101 102     public String getOpenId() {103         return openId;104     }105 106     public void setOpenId(String openId) {107         this.openId = openId;108     }109 110     public String getIs_lost() {111         return is_lost;112     }113 114     public void setIs_lost(String is_lost) {115         this.is_lost = is_lost;116     }117 118     public String getProvince() {119         return province;120     }121 122     public void setProvince(String province) {123         this.province = province;124     }125 126     public String getCity() {127         return city;128     }129 130     public void setCity(String city) {131         this.city = city;132     }133 134     public String getYear() {135         return year;136     }137 138     public void setYear(String year) {139         this.year = year;140     }141 142     public String getNickname() {143         return nickname;144     }145 146     public void setNickname(String nickname) {147         this.nickname = nickname;148     }149 150     public String getFigureurl() {151         return figureurl;152     }153 154     public void setFigureurl(String figureurl) {155         this.figureurl = figureurl;156     }157 158     public String getFigureurl_1() {159         return figureurl_1;160     }161 162     public void setFigureurl_1(String figureurl_1) {163         this.figureurl_1 = figureurl_1;164     }165 166     public String getFigureurl_2() {167         return figureurl_2;168     }169 170     public void setFigureurl_2(String figureurl_2) {171         this.figureurl_2 = figureurl_2;172     }173 174     public String getFigureurl_qq_1() {175         return figureurl_qq_1;176     }177 178     public void setFigureurl_qq_1(String figureurl_qq_1) {179         this.figureurl_qq_1 = figureurl_qq_1;180     }181 182     public String getFigureurl_qq_2() {183         return figureurl_qq_2;184     }185 186     public void setFigureurl_qq_2(String figureurl_qq_2) {187         this.figureurl_qq_2 = figureurl_qq_2;188     }189 190     public String getGender() {191         return gender;192     }193 194     public void setGender(String gender) {195         this.gender = gender;196     }197 198     public String getIs_yellow_vip() {199         return is_yellow_vip;200     }201 202     public void setIs_yellow_vip(String is_yellow_vip) {203         this.is_yellow_vip = is_yellow_vip;204     }205 206     public String getVip() {207         return vip;208     }209 210     public void setVip(String vip) {211         this.vip = vip;212     }213 214     public String getYellow_vip_level() {215         return yellow_vip_level;216     }217 218     public void setYellow_vip_level(String yellow_vip_level) {219         this.yellow_vip_level = yellow_vip_level;220     }221 222     public String getLevel() {223         return level;224     }225 226     public void setLevel(String level) {227         this.level = level;228     }229 230     public String getIs_yellow_year_vip() {231         return is_yellow_year_vip;232     }233 234     public void setIs_yellow_year_vip(String is_yellow_year_vip) {235         this.is_yellow_year_vip = is_yellow_year_vip;236     }237 }

⒉编写一个QQ API接口用于获取QQ用户信息

1 package cn.coreqi.social.qq.api; 2  3 import cn.coreqi.social.qq.entities.QQUserInfo; 4  5 public interface QQ { 6     /** 7      * 返回QQ中的用户信息 8      * @return 9      */10     QQUserInfo getUserInfo();11 }

⒊编写一个QQ API接口实现

1 package cn.coreqi.social.qq.api.impl; 2  3 import cn.coreqi.social.qq.api.QQ; 4 import cn.coreqi.social.qq.entities.QQUserInfo; 5 import com.fasterxml.jackson.databind.ObjectMapper; 6 import org.apache.commons.lang.StringUtils; 7 import org.springframework.social.oauth2.AbstractOAuth2ApiBinding; 8 import org.springframework.social.oauth2.TokenStrategy; 9 10 import java.io.IOException;11 12 /**13  * 获取用户信息14  * 不能声明为单例,因为每个用户的验证是不同的15  */16 public class QQImpl extends AbstractOAuth2ApiBinding implements QQ {17 18     private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";    //获取openid的请求地址19     private static final String URL_GET_USERINFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s";   //获取用户信息的请求地址20 21     private String appid;   //申请QQ登录成功后,分配给应用的appid22     private String openid;  //用户的ID,与QQ号码一一对应。23 24     private ObjectMapper objectMapper = new ObjectMapper(); //用于序列化Json数据25 26     public QQImpl(String accessToken,String appid){27         super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);   //将token作为查询参数28         this.appid = appid;29 30         String url = String.format(URL_GET_OPENID,accessToken); //拼接成最终的openid的请求地址31         String result = getRestTemplate().getForObject(url,String.class);32 33         System.out.println(result);34 35         this.openid = StringUtils.substringBetween(result,"\"openid\":\"","\"}");36 37     }38 39     @Override40     public QQUserInfo getUserInfo() {41         String url = String.format(URL_GET_USERINFO,appid,openid);  拼接成最终的获取用户信息的请求地址42         String result = getRestTemplate().getForObject(url,String.class);43         System.out.println(result);44         QQUserInfo userInfo = null;45         try {46             userInfo =  objectMapper.readValue(result,QQUserInfo.class);47             userInfo.setOpenId(openid);48             return userInfo;49         } catch (Exception e) {50             throw new RuntimeException("获取用户信息失败",e);51         }52     }53 }

⒋编写QQ OAuth2认证流程模板类。

1 package cn.coreqi.social.qq.connect; 2  3 import org.apache.commons.lang.StringUtils; 4 import org.slf4j.Logger; 5 import org.slf4j.LoggerFactory; 6 import org.springframework.http.converter.StringHttpMessageConverter; 7 import org.springframework.social.oauth2.AccessGrant; 8 import org.springframework.social.oauth2.OAuth2Template; 9 import org.springframework.util.MultiValueMap;10 import org.springframework.web.client.RestTemplate;11 import java.nio.charset.Charset;12 13 public class QQOAuth2Template extends OAuth2Template {14 15     private Logger logger = LoggerFactory.getLogger(getClass());16 17     public QQOAuth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {18         super(clientId, clientSecret, authorizeUrl, accessTokenUrl);19         setUseParametersForClientAuthentication(true);20     }21 22     @Override23     protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap
parameters) {24 String responseStr = getRestTemplate().postForObject(accessTokenUrl, parameters, String.class);25 26 logger.info("获取accessToke的响应:"+responseStr);27 28 String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(responseStr, "&");29 30 String accessToken = StringUtils.substringAfterLast(items[0], "=");31 Long expiresIn = new Long(StringUtils.substringAfterLast(items[1], "="));32 String refreshToken = StringUtils.substringAfterLast(items[2], "=");33 34 return new AccessGrant(accessToken, null, refreshToken, expiresIn);35 }36 37 @Override38 protected RestTemplate createRestTemplate() {39 RestTemplate restTemplate = super.createRestTemplate();40 restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));41 return restTemplate;42 }43 }

⒌编写QQ的OAuth2流程处理器的提供器

1 package cn.coreqi.social.qq.connect; 2  3 import cn.coreqi.social.qq.api.QQ; 4 import cn.coreqi.social.qq.api.impl.QQImpl; 5 import org.springframework.social.oauth2.AbstractOAuth2ServiceProvider; 6  7 /** 8  * 泛型是API接口的类型 9  */10 public class QQServiceProvider extends AbstractOAuth2ServiceProvider
{11 12 private static final String URL_AUTHORIZE = "https://graph.qq.com/oauth2.0/authorize"; //获取授权码地址13 private static final String URL_ACCESS_TOKEN = "https://graph.qq.com/oauth2.0/token"; //获取用户令牌地址14 15 private String appId;16 17 18 public QQServiceProvider(String appId,String appSecret) {19 super(new QQOAuth2Template(appId,appSecret,URL_AUTHORIZE,URL_ACCESS_TOKEN));20 this.appId = appId;21 }22 23 @Override24 public QQ getApi(String accessToken) {25 return new QQImpl(accessToken,appId);26 }27 }

⒍编写QQ API适配器,将从QQ API拿到的用户数据模型转换为Spring Social的标准用户数据模型。

1 package cn.coreqi.social.qq.connect; 2  3 import cn.coreqi.social.qq.api.QQ; 4 import cn.coreqi.social.qq.entities.QQUserInfo; 5 import org.springframework.social.connect.ApiAdapter; 6 import org.springframework.social.connect.ConnectionValues; 7 import org.springframework.social.connect.UserProfile; 8  9 import java.io.IOException;10 11 /**12  *  泛型是指当前API适配器适配API的类型是什么13  */14 public class QQAdapter implements ApiAdapter
{15 16 /**17 * 用来测试当前的API是否可用18 * @param qq19 * @return20 */21 @Override22 public boolean test(QQ qq) {23 return true;24 }25 26 /**27 * 将服务提供商个性化的用户信息映射到ConnectionValues标准的数据化结构上28 * @param qq29 * @param connectionValues30 */31 @Override32 public void setConnectionValues(QQ qq, ConnectionValues connectionValues) {33 QQUserInfo userInfo = qq.getUserInfo();34 connectionValues.setDisplayName(userInfo.getNickname()); //显示的用户名称35 connectionValues.setImageUrl(userInfo.getFigureurl_qq_1()); //用户的头像36 connectionValues.setProfileUrl(null); //个人主页37 connectionValues.setProviderUserId(userInfo.getOpenId()); //QQ的唯一标识38 }39 40 /**41 * 和上面的方法类似42 * @param qq43 * @return44 */45 @Override46 public UserProfile fetchUserProfile(QQ qq) {47 return null;48 }49 50 /**51 *52 * @param qq53 * @param s54 */55 @Override56 public void updateStatus(QQ qq, String s) {57 58 }59 }

⒎创建QQ连接工厂

1 package cn.coreqi.social.qq.connect; 2  3 import cn.coreqi.social.qq.api.QQ; 4 import org.springframework.social.connect.support.OAuth2ConnectionFactory; 5  6 public class QQConnectionFactory extends OAuth2ConnectionFactory
{ 7 8 /** 9 *10 * @param providerId 我们给服务提供商的唯一标识11 * @param appId 服务提供商给的AppId12 * @param appSecret 服务提供商给的App密码13 */14 public QQConnectionFactory(String providerId,String appId,String appSecret) {15 super(providerId, new QQServiceProvider(appId,appSecret), new QQAdapter());16 }17 }

⒏创建UserConnection数据表

1 create table UserConnection (userId varchar(255) not null, 2     providerId varchar(255) not null, 3     providerUserId varchar(255), 4     `rank` int not null, 5     displayName varchar(255), 6     profileUrl varchar(512), 7     imageUrl varchar(512), 8     accessToken varchar(512) not null, 9     secret varchar(512),10     refreshToken varchar(512),11     expireTime bigint,12     primary key (userId, providerId, providerUserId));13 create unique index UserConnectionRank on UserConnection(userId, providerId, `rank`);

⒐为用户服务类实现SocialUserDetailsService ,用于从数据库中通过QQ Id 拿到业务系统用户

1 /** 2  *  3  */ 4 package cn.coreqi.security; 5  6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.security.core.authority.AuthorityUtils;10 import org.springframework.security.core.userdetails.UserDetails;11 import org.springframework.security.core.userdetails.UserDetailsService;12 import org.springframework.security.core.userdetails.UsernameNotFoundException;13 import org.springframework.security.crypto.password.PasswordEncoder;14 import org.springframework.social.security.SocialUser;15 import org.springframework.social.security.SocialUserDetails;16 import org.springframework.social.security.SocialUserDetailsService;17 import org.springframework.stereotype.Component;18 19 /**20  * @author fanqi21  *22  */23 @Component24 public class MyUserDetailsService implements UserDetailsService, SocialUserDetailsService {25 26     private Logger logger = LoggerFactory.getLogger(getClass());27     28     @Autowired29     private PasswordEncoder passwordEncoder;30 31     /*32      * (non-Javadoc)33      * 34      * @see org.springframework.security.core.userdetails.UserDetailsService#35      * loadUserByUsername(java.lang.String)36      */37     @Override38     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {39         logger.info("表单登录用户名:" + username);40         return buildUser(username);41     }42 43     @Override44     public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException {45         logger.info("设计登录用户Id:" + userId);46         return buildUser(userId);47     }48 49     private SocialUserDetails buildUser(String userId) {50         // 根据用户名查找用户信息51         //根据查找到的用户信息判断用户是否被冻结52         String password = passwordEncoder.encode("123456");53         logger.info("数据库密码是:"+password);54         return new SocialUser(userId, password,55                 true, true, true, true,56                 AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));57     }58 59 }

⒑创建QQ登陆配置类

1 package cn.coreqi.social.qq.connect; 2  3 import org.springframework.boot.autoconfigure.social.SocialAutoConfigurerAdapter; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.social.connect.ConnectionFactory; 6  7 /** 8  * QQ登录配置 9  */10 @Configuration11 public class QQAutoConfig extends SocialAutoConfigurerAdapter {12     @Override13     protected ConnectionFactory
createConnectionFactory() {14 String providerId = "qq"; //第三方id,用来决定发起第三方登录的url,默认是weixin15 String appId = "";16 String appSecret = "";17 return new QQConnectionFactory(providerId, appId, appSecret);18 }19 }

 ⒒自定义我们自己的SpringSocial配置

1 package cn.coreqi.social.config; 2  3 import org.springframework.social.security.SocialAuthenticationFilter; 4 import org.springframework.social.security.SpringSocialConfigurer; 5  6 public class CoreqiSpringSocialConfig extends SpringSocialConfigurer { 7  8     /** 9      *10      * @param object11      * @param 
12 * @return13 */14 @Override15 protected
T postProcess(T object) {16 SocialAuthenticationFilter filter = (SocialAuthenticationFilter)super.postProcess(object);17 filter.setFilterProcessesUrl("/coreqi/auth");18 return (T) filter;19 }20 }
SpringSocialConfigurer 会在 configure方法中声明一个 SocialAuthenticationFilter,我们可以继承SpringSocialConfigurer达到自定义我们的SpringSocial配置需求。 ⒓声明一个SpringSocial的配置类
1 package cn.coreqi.social.config; 2  3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.security.crypto.encrypt.Encryptors; 7 import org.springframework.social.config.annotation.EnableSocial; 8 import org.springframework.social.config.annotation.SocialConfigurerAdapter; 9 import org.springframework.social.connect.ConnectionFactoryLocator;10 import org.springframework.social.connect.ConnectionSignUp;11 import org.springframework.social.connect.UsersConnectionRepository;12 import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository;13 import org.springframework.social.connect.web.ProviderSignInUtils;14 import org.springframework.social.security.SpringSocialConfigurer;15 16 import javax.sql.DataSource;17 18 @Configuration19 @EnableSocial20 public class SocialConfig extends SocialConfigurerAdapter {21 22     @Autowired23     private DataSource dataSource;24 25     @Autowired(required = false)26     private ConnectionSignUp connectionSignUp;27 28     /**29      *30      * @param connectionFactoryLocator  作用是去根据条件去查找应该用那个connectionFactory,因为系统中可能有很多的connectionFactory。31      * @return32      */33     @Override34     public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {35         //第三个参数的作用是把插入到数据库的数据进行加解密36         JdbcUsersConnectionRepository jdbcUsersConnectionRepository = new JdbcUsersConnectionRepository(dataSource,connectionFactoryLocator, Encryptors.noOpText());37         //jdbcUsersConnectionRepository.setTablePrefix(); //设置数据表的前缀38         if(connectionSignUp != null){39             jdbcUsersConnectionRepository.setConnectionSignUp(connectionSignUp);40         }41         return jdbcUsersConnectionRepository;42     }43 44     /**45      * 声明后还需要加在SpringSecurity过滤器链上46      * @return47      */48     @Bean49     public SpringSocialConfigurer coreqiSocialSecurityConfig(){50         CoreqiSpringSocialConfig config = new CoreqiSpringSocialConfig();51         config.signupUrl("/registry");  //当从业务系统中无法找到OAuth快捷登陆的用户,那么将用户引导到注册页面中52         return config;53     }54 55     //1.注册过程中如何拿到SpringSocial信息56     //2.注册完成后如何把业务系统的用户ID传给SpringSocial57     @Bean58     public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator){59         return new ProviderSignInUtils(connectionFactoryLocator,getUsersConnectionRepository(connectionFactoryLocator));60     }61 }

 

⒔应用我们的过滤器配置
1 package cn.coreqi.config; 2  3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 import org.springframework.social.security.SpringSocialConfigurer; 7  8 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 9     @Autowired10     private SpringSocialConfigurer coreqiSocialSecurityConfig;11     @Override12     protected void configure(HttpSecurity http) throws Exception {13         http.apply(coreqiSocialSecurityConfig);14     }15 }

 ⒕

1 package cn.coreqi.social.qq.connect; 2  3 import org.springframework.social.connect.Connection; 4 import org.springframework.social.connect.ConnectionSignUp; 5 import org.springframework.stereotype.Component; 6  7 /** 8  * 当没有从数据库中查找到第三方登录的用户,那么将执行ConnectionSignUp的execute方法生成新的用户id并存储到数据库中 9  */10 @Component11 public class CoreqiConnectionSignUp implements ConnectionSignUp {12     @Override13     public String execute(Connection
connection) {14 return connection.getDisplayName();15 }16 }

 

 

 

转载于:https://www.cnblogs.com/fanqisoft/p/10691234.html

你可能感兴趣的文章
Educational Codeforces Round 9 D. Longest Subsequence dp
查看>>
Educational Codeforces Round 11 D. Number of Parallelograms 暴力
查看>>
C#:只读字段, 匿名类型
查看>>
IOS TableView的Delegate Methods-tableView didSelectRowAtIndexPath
查看>>
一条sql
查看>>
TF400916错误修复办法
查看>>
【dp】HDU_2955
查看>>
Android 面试精华题目总结
查看>>
shell编程
查看>>
leetcode:8. String to Integer (atoi)
查看>>
archive 打包出错 apple mach-o linker (id) error
查看>>
深度优先用法之检测有无环
查看>>
拆单发货-分布页
查看>>
Intellij Idea 2017创建web项目及tomcat部署实战
查看>>
Visualizing CNN Layer in Keras
查看>>
Java书籍经典Top10
查看>>
iperf——网络性能测试工具
查看>>
sysctl.conf网络内核参数说明(转)
查看>>
谷歌 chrome 浏览器开发者工具打不开的解决方法
查看>>
PHP 简单实现webSocket
查看>>