在早期我写过一篇spring social理解的文章,介绍了一些spring social的概念,但是没有提供一个例子。在这篇博客中,提供一个简单的spring social的例子,实现 百度登录,那为什么不实现QQ登录或微信登录,主要是在QQ和微信上申请应用比较麻烦,没有百度方便,在文章的末尾我也放出 QQ登录 和 微信登录 的源码。2018-11-28号增加了一个 github 的登录。

实现功能:

1,实现百度登录

2,与 spring security 整合

3,当是第一次使用百度登录时,自动在业务中中创建一个用户。

4,显示获取到百度用户的用户昵称和图像等

与spring security整合注意事项:

1,在spring security的过滤器链中增加 SocialAuthenticationFilter 来判断用户是否是社交登录,默认拦截 /auth 开头的请求。该过滤器在 SpringSocialConfigurer 类中配置的。

2,当我们使用百度登录成功后,如何和我们自动业务系统中的userId进行关联,是有UserConnection表进行关联的。

3,需要实现 SocialUserDetailsService 接口,返回业务系统中的用户信息,用户id就是业务系统中的userId.

开发一个社交登录

1,看spring social官网提供的步骤

前置条件

1,在百度开发者中心创建一个应用,设置好回调 url , 假设此处为  http://www.huan1993.com/auth/baidu

2,记录好上一步的 apikey securityKey

3,在本地 hosts 文件中配置 127.0.0.1 www.huan1993.com

4,在数据库中创建 UserConnection 表,表名不可变,但是可以加前缀。建表语句在 JdbcConnectionRepository.java 文件下方。这张表维护了  业务系统张三(userId)在百度(providerId)上的唯一用户标识(providerUserId)

实现步骤

1,新建 BaiduUserInfo 类,此类是保存着用户在百度上的基本信息

/**
* 百度的用户信息
*
* @author huan.fu
* @date 2018/9/27 - 16:58
*/
@NoArgsConstructor
@Data
public class BaiduUserInfo {
@SerializedName("userid")
private String userId;
private String username;
@SerializedName("realname")
private String realName;
@SerializedName("userdetail")
private String userDetail;
private String birthday;
private String marriage;
private String portrait;
private String sex;
private String blood;
private String constellation;
private String figure;
private String education;
private String trade;
private String job;
@SerializedName("birthday_year")
private String birthdayYear;
@SerializedName("birthday_month")
private String birthdayMonth;
@SerializedName("birthday_day")
private String birthdayDay;
}

2,新建 Baidu 接口类,申明一个方法用于获取百度的基本信息

/**
* baidu api 接口
*
* @author huan.fu
* @date 2018/9/27 - 17:00
*/
public interface Baidu { /**
* 获取百度用户信息
*
* @return
*/
BaiduUserInfo getUserInfo(); }

3,新建 BaiduTemplate.java 类,获取具体的百度用户信息

/**
* 百度接口实现,此处用户获取用户在百度上的基本信息
*
* @author huan.fu
* @date 2018/9/27 - 17:01
*/
@Slf4j
public class BaiduTemplate extends AbstractOAuth2ApiBinding implements Baidu { @Getter
private String userInfoUrl;
@Getter
private String accessToken; public BaiduTemplate(String accessToken, String userInfoUrl) {
/**
* 调用父类 2 个参数的构造方法,
* TokenStrategy.ACCESS_TOKEN_PARAMETER 父类会自动将此参数带上,默认是放在请求头Authorization头中
*/
super(accessToken, TokenStrategy.OAUTH_TOKEN_PARAMETER);
this.userInfoUrl = userInfoUrl;
this.accessToken = accessToken;
} @Override
public BaiduUserInfo getUserInfo() {
String userInfo = getRestTemplate().getForObject(String.format(this.getUserInfoUrl(), this.getAccessToken()), String.class);
log.info("获取的百度用户信息为:[{}]", userInfo);
return new Gson().fromJson(userInfo, BaiduUserInfo.class);
}
}

4,新建 BaiduAdapter.java 类,用于将百度的用户信息转换成Connection的标准信息

/**
* 百度的 api 适配器
*
* @author huan.fu
* @date 2018/9/27 - 17:10
*/
public class BaiduAdapter implements ApiAdapter<Baidu> {
@Override
public boolean test(Baidu api) {
return true;
} @Override
public void setConnectionValues(Baidu api, ConnectionValues values) {
BaiduUserInfo userInfo = api.getUserInfo();
values.setDisplayName(userInfo.getRealName() == null ? userInfo.getUsername() : userInfo.getRealName());
values.setImageUrl(String.format("http://tb.himg.baidu.com/sys/portrait/item/%s", userInfo.getPortrait()));
values.setProfileUrl(null);
values.setProviderUserId(userInfo.getUserId());
} @Override
public UserProfile fetchUserProfile(Baidu api) {
return null;
} @Override
public void updateStatus(Baidu api, String message) { }
}

5,新建 BaiduOauth2Template.java 类,用于走oauth2授权码流程,获取到真正的访问令牌

/**
* 走完oauth2流程
*
* @author huan.fu
* @date 2018/9/27 - 17:14
*/
@Slf4j
public class BaiduOauth2Template extends OAuth2Template { public BaiduOauth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {
super(clientId, clientSecret, authorizeUrl, accessTokenUrl);
// 设置为true,将客户端凭证作为参数传递给提供者,而不是使用HTTP基本身份验证 createRestTemplate() 此方法中如果useParametersForClientAuthentication=false将会使用basic认证
setUseParametersForClientAuthentication(true);
} @Override
public String buildAuthenticateUrl(OAuth2Parameters parameters) {
StringBuilder builder = new StringBuilder(super.buildAuthenticateUrl(parameters));
// force_login=1 在百度登录中表示:force_login:非必须参数,如传递“force_login=1”,则加载登录页时强制用户输入用户名和口令,不会从cookie中读取百度用户的登陆状态。
builder.append("&force_login=1");
log.info("获取code的访问url:[{}]", builder.toString());
return builder.toString();
}
}

6,创建一个 BaiduServiceProvider.java类 封装 api 和 oauth2template

/**
* 服务提供商
*
* @author huan.fu
* @date 2018/9/27 - 17:20
*/
@Getter
public class BaiduServiceProvider extends AbstractOAuth2ServiceProvider<Baidu> { private String userInfoUrl; public BaiduServiceProvider(String clientId, String clientSecret, String userInfoUrl, String authorizeUrl, String accessTokenUrl) {
super(new BaiduOauth2Template(clientId, clientSecret, authorizeUrl, accessTokenUrl));
this.userInfoUrl = userInfoUrl;
} @Override
public Baidu getApi(String accessToken) {
return new BaiduTemplate(accessToken, this.getUserInfoUrl());
}
}

7,创建 BaiduConnectionFactory 用来产生连接

/**
* 百度 connection fatory
*
* @author huan.fu
* @date 2018/9/27 - 17:22
*/
public class BaiduConnectionFactory extends OAuth2ConnectionFactory<Baidu> { public BaiduConnectionFactory(String providerId, String clientId, String userInfoUrl, String clientSecret, String authorizeUrl, String accessTokenUrl) {
super(
providerId,
new BaiduServiceProvider(clientId, clientSecret, userInfoUrl, authorizeUrl, accessTokenUrl),
new BaiduAdapter()
);
}
}

8,创建 BaiduConnectionSignUp 类用来为用户在业务系统注册一个用户

/**
* 一个简单的注册处理
*
* @author huan.fu
* @date 2018/9/27 - 17:29
*/
@Slf4j
public class BaiduConnectionSignUp implements ConnectionSignUp { /**
* 可以在此方法中进行简单的用户注册
*
* @param connection
* @return 用户注册后, 业务系统中的 用户编号
*/
@Override
public String execute(Connection<?> connection) {
ConnectionData connectionData = connection.createData();
log.info("用户在系统中是第一次使用百度登录,系统自动给用户进行注册一个用户,返回用户在业务系统中的id:[{}]", connectionData.getProviderUserId());
return connectionData.getProviderUserId();
}
}

9,百度的登录社交配置

社交登录中需要用到的配置属性

/**
* 百度 社交登录配置属性
*
* @author huan.fu
* @date 2018/9/27 - 15:30
*/
@ConfigurationProperties(prefix = "spring.social.baidu")
@Data
public class BaiduProperties {
private String providerId;
private String clientId;
private String clientSecret;
private String userInfoUrl;
private String authorizeUrl;
private String accessTokenUrl;
}

社交登录配置

/**
* 百度 社交登录的自动配置
*
* @author huan.fu
* @date 2018/9/27 - 17:35
*/
@Configuration
@EnableSocial
@ConditionalOnProperty(prefix = "spring.social.baidu", name = "provider-id")
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class BaiduAutoAuthConfig extends SocialAutoConfigurerAdapter { @Autowired
private BaiduProperties baiduProperties; @Autowired
private DataSource dataSource; @Autowired
private BaiduAuthenticationSuccessHandlerSuccessHandler baiduAuthenticationSuccessHandlerSuccessHandler; @Override
protected ConnectionFactory<?> createConnectionFactory() {
return new BaiduConnectionFactory(
baiduProperties.getProviderId(),
baiduProperties.getClientId(),
baiduProperties.getUserInfoUrl(),
baiduProperties.getClientSecret(),
baiduProperties.getAuthorizeUrl(),
baiduProperties.getAccessTokenUrl()
);
} @Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
// 第三个参数表数保存到数据库中的数据是以何种方式进行存储的,此处明文进行存储
JdbcUsersConnectionRepository jdbcUsersConnectionRepository = new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText());
// 设置 UserConnection 表的前缀,此处不进行设置
jdbcUsersConnectionRepository.setTablePrefix("");
jdbcUsersConnectionRepository.setConnectionSignUp(new BaiduConnectionSignUp());
return jdbcUsersConnectionRepository;
} /**
* 将 spring social 加入到 spring security 的过滤器链中
*
* @return
*/
@Bean
public SpringSocialConfigurer springSocialConfigurer() {
return new SpringSocialConfigurer() {
@Override
protected <T> T postProcess(T object) {
SocialAuthenticationFilter filter = (SocialAuthenticationFilter) object;
filter.setAuthenticationSuccessHandler(baiduAuthenticationSuccessHandlerSuccessHandler);
return (T) filter;
}
};
} /**
* 登录帮助类
*
* @param connectionFactoryLocator
* @param usersConnectionRepository
* @return
*/
@Bean
public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator, UsersConnectionRepository usersConnectionRepository) {
return new ProviderSignInUtils(new HttpSessionSessionStrategy(), connectionFactoryLocator, usersConnectionRepository);
}
}

10,spring security 配置

 11,登录页面

 12,用户信息显示

完整代码

百度登录:https://gitee.com/huan1993/spring-social-parent/tree/feature%2Fbaidu/

github登录:https://gitee.com/huan1993/spring-social-parent/tree/feature%2Fgithub/

QQ登录:https://gitee.com/huan1993/spring-social-parent/tree/feature%2Fqq/

微信登录:https://gitee.com/huan1993/spring-social-parent/tree/feature%2Fweixin/

百度&QQ&微信登录:https://gitee.com/huan1993/spring-social-parent/tree/master/

spring social实现百度登录的更多相关文章

  1. Spring Security 源码分析(四):Spring Social实现微信社交登录

    社交登录又称作社会化登录(Social Login),是指网站的用户可以使用腾讯QQ.人人网.开心网.新浪微博.搜狐微博.腾讯微博.淘宝.豆瓣.MSN.Google等社会化媒体账号登录该网站. 前言 ...

  2. Spring Security构建Rest服务-0102-Spring Social开发第三方登录之qq登录

    图一 基于SpringSocial实现qq登录,要走一个OAuth流程,拿到服务提供商qq返回的用户信息. 由上篇介绍的可知,用户信息被封装在了Connection里,所以最终要拿到Connectio ...

  3. Spring Security构建Rest服务-1001-spring social开发第三方登录之spring social基本原理

    OAuth协议是一个授权协议,目的是让用户在不将服务提供商的用户名密码交给第三方应用的条件下,让第三方应用可以有权限访问用户存在服务提供商上的资源. 接着上一篇说的,在第三方应用获取到用户资源后,如果 ...

  4. 社交媒体登录Spring Social的源码解析

    在上一篇文章中我们给大家介绍了OAuth2授权标准,并且着重介绍了OAuth2的授权码认证模式.目前绝大多数的社交媒体平台,都是通过OAuth2授权码认证模式对外开放接口(登录认证及用户信息接口等). ...

  5. spring social理解

    现在互联网飞速发展,人们每天在互联网上冲浪,获取各种信息.各大网站为了方便用户的登录,提供了各式各样的社交登录,比如:QQ.微信和微博登录等.这些主流的社交登录大多是基于oauth协议进行实现,spr ...

  6. C#模拟百度登录

    目录: 1.fiddler解析百度登录地址 2.处理传入参数 1.fiddler解析百度登录地址 因工作需要,所以研究了下百度的登陆.首先打开https://passport.baidu.com/v2 ...

  7. POST模拟百度登录和自动发帖

    这里用HttpClient发包模拟百度登录和发帖,验证码部分采用机器下载人工识别. 登陆百度的原理:1. 访问https://passport.baidu.com/v2/api/?getapi& ...

  8. opencart 百度登录和百度钱包支付插件 响应式适应pc/mobile

    OpenCart(http://www.opencart.com/,http://www.opencartchina.com/)是国外著名的开源电子商务系统, 优势在于前台界面的设计非常适合欧美购物者 ...

  9. spring security使用自定义登录界面后,不能返回到之前的请求界面的问题

    昨天因为集成spring security oauth2,所以对之前spring security的配置进行了一些修改,然后就导致登录后不能正确跳转回被拦截的页面,而是返回到localhost根目录. ...

随机推荐

  1. MacOS安装和卸载Java

    ​ 安装java 下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 设 ...

  2. npm 设置同时从多个包源加载包的方法

    随着前后端分离技术的发展成熟,越来越来越多的后台系统甚至前端系统采用前后端分离方式,在大型前后端分离系统中,前端往往包含大量的第三方js 包的引用,各个第三方包又可能依赖另外一个第三方包,因此急需要一 ...

  3. 法术迸发(Spellburst)

    描述 法术迸发 (EN:Spellburst ) 是一种在<通灵学园>中加入的关键字异能,在玩家打出一张法术牌后触发,只能触发一次. 若随从在法术结算过程中死亡,则不会触发效果 思路 首先 ...

  4. 最新版微软视窗(Windows)作业系统下载(2020-08-19)

    为了更好的使用WSL(Windows Subsystem For Linux),不得不用最新的windows 10 2004版了,这个版本的WSL已经是第二版了,即WSL2.下面给出下载地址 系统发布 ...

  5. Dapr实战(三)状态管理

    状态管理解决了什么 分布式应用程序中的状态可能很有挑战性. 例如: 应用程序可能需要不同类型的数据存储. 访问和更新数据可能需要不同的一致性级别. 多个用户可以同时更新数据,这需要解决冲突. 服务必须 ...

  6. [手机编程]Aid Learning--换源+数据库安装

    换源+MYSQL安装 Aid Learning下载安装 http://www.aidlearning.net/ 切换源 打开Terminal复制回车即可 cd /etc/apt/&& ...

  7. php/awk 处理csv 使用 SplFileObject 操作文件

    取第5列,去掉开头结尾的引号,匹配以http://, https://, ftp://开头的行 * awk awk -F"," 'str=gsub(/(^\"*)|(\& ...

  8. 『Python』多进程

    Python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在Python中大部分情况需要使用多进程.Python提供了multiprocessin ...

  9. Loj#6053-简单的函数【Min25筛】

    正题 题目链接:https://loj.ac/p/6053 题目大意 定义一个积性函数\(f(p^c)=p\ xor\ c\),求\(\sum_{i=1}^nf(i)\) 解题思路 异或这个东西不太好 ...

  10. P3235-[HNOI2014]江南乐【整除分块,SG函数】

    正题 题目链接:https://www.luogu.com.cn/problem/P3235 题目大意 \(T\)组游戏,固定给出\(F\).每组游戏有\(n\)个石头,每次操作的人可以选择一个数量不 ...