Spring OAuth2 GitHub 自定义登录信息
# 相关代码
https://github.com/mofadeyunduo/money
0.1.3-SNAPSHOT
security 模块中
# 原因
最近在做一款管理金钱的网站进行自娱自乐,发现没有安全控制岂不是大家都知道我的工资了(一脸黑线)?
最近公司也在搞 Spring OAuth2,当时我没有时间(其实那时候不想搞)就没做,现在回头来学习学习。
Spring OAuth2 官方的教程写的比较少,实用性比较差。
# 教程内容
- Spring OAuth2 Github SSO
- 替换认证过的 Spring Security Authentication 对象
- 后端设置 Cookie 实现 Remember-Me 功能
# Github 登录
Spring OAuth2 Github,官网写的已经比较详细了。
要注意的是必须要配置两个 Filter:
- OAuth2ClientAuthenticationProcessingFilter ,用于处理 OAuth2 流程。
- OAuth2ClientContextFilter,用于触发跳转到 OAuth2 请求。
P.S. 这很诡异,我不知道 Spring OAuth2 为什么要这么做。
# 替换认证过的 Spring Security Authentication
步骤:
- 重写方法 getPrincipal,把 Authentication 中的 Principal 换成用户信息对象。
- 最好设置 AuthenticationSuccessHandler,默认的 AuthenticationSuccessHandler 会跳转到主页,并将 Cookie 清空,影响 RememberMeServices 认证。
@Override
protected Object getPrincipal(Map<String, Object> map) {
String principal = String.class.cast(map.get("name"));
// 从数据库读取用户
UserWithAccount userWithAccount = userAndAccountService.getByPrincipalAndType(principal, AccountType.GITHUB);
// 未获取到用户信息,保存
if (Objects.isNull(userWithAccount)) {
Account newAccount = new Account(null, AccountType.GITHUB, principal, new Gson().toJson(map));
userWithAccount = userAndAccountService.accountSignup(newAccount);
}
// 替换原来的 OAuth2Authentication
return userWithAccount;
}
githubFilter.setAuthenticationSuccessHandler(new GithubAuthenticationSuccessHandler());
# 设置 Cookie
- 实现 UserDetailServices。
- 用 UserDetailServices 构造 RememberMeServices。这里采用的 RememberMeServices 的具体实现是 TokenBasedRememberMeServices。TokenBasedRememberMeServices 会用 UserDetailServices 构造 Authentication 的 Principal 对象。还有一个构造参数(key)是指定盐,指定一个值,该值在应用反复重启的时要保持不变。顺便提一下,TokenBasedRememberMeServices 加密是根据 UserDetailServices 构造出的 UserDetails 中的 username、password、时间戳、构造参数 key 进行 MD5 和 Base64 加密和解密。
- 在 OAuth2ClientAuthenticationProcessingFilter 和继承类 WebSecurityConfigurerAdapter 的方法 configure 注册 RememberMeServices。注册到 OAuth2ClientAuthenticationProcessingFilter 是为了在 OAuth2 认证成功或者失败之后设置 Cookie。在 configure 注册 RememberMeServices 是为了利用 Cookie 自动登录。
public class CachingUserDetailsService implements UserDetailsService {
private static final String USER_KEY = "user:%s";
private StringRedisTemplate stringRedisTemplate;
private UserAndAccountService userAndAccountService;
public CachingUserDetailsService(StringRedisTemplate stringRedisTemplate, UserAndAccountService userAndAccountService) {
this.stringRedisTemplate = stringRedisTemplate;
this.userAndAccountService = userAndAccountService;
}
public UserDetails loadUserByUsername(String username) {
String actualKey = String.format(USER_KEY, username);
UserWithAccount userWithAccount;
String userWithAccountJson = stringRedisTemplate.opsForValue().get(actualKey);
if (StringUtils.isEmpty(userWithAccountJson)) {
userWithAccount = userAndAccountService.getByUserId(Integer.parseInt(username));
stringRedisTemplate.opsForValue().set(actualKey, new Gson().toJson(userWithAccount));
} else {
userWithAccount = new Gson().fromJson(userWithAccountJson, UserWithAccount.class);
}
return userWithAccount;
}
}
@Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices tokenBasedRememberMeServices = new TokenBasedRememberMeServices(REMEMBER_ME_KEY, userDetailsService());
tokenBasedRememberMeServices.setAlwaysRemember(true);
tokenBasedRememberMeServices.setTokenValiditySeconds(ONE_DAY_IN_SECONDS);
return tokenBasedRememberMeServices;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.key(REMEMBER_ME_KEY)
.rememberMeServices(rememberMeServices());
http
.addFilterBefore(oAuth2ClientAuthenticationProcessingFilter(), BasicAuthenticationFilter.class); // Github OAuth2 登录的 Filter
} @Bean
public OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter() {
OAuth2ClientAuthenticationProcessingFilter githubFilter = new OAuth2ClientAuthenticationProcessingFilter("/security/oauth2/github");
OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(githubClient(), oauth2ClientContext);
githubFilter.setAllowSessionCreation(false);
githubFilter.setRestTemplate(facebookTemplate);
githubFilter.setTokenServices(new GithubUserInfoTokenServices(githubResource().getUserInfoUri(), githubClient().getClientId(), userAndAccountService));
githubFilter.setRememberMeServices(rememberMeServices());
githubFilter.setAuthenticationSuccessHandler(new GithubAuthenticationSuccessHandler());
return githubFilter;
}
# 后记
我本来预估一周时间就把我项目的安全控制模块给开发完,结果被 Spring Oauth2 拖了一周。由于对 Spring 核心概念也不是特别熟悉,看代码也比较费事(虽然大部分看得懂)。最近一段时间准备写一套 IoC 方面的代码。
我现在所在的公司之前有个人挺厉害,自己写了一套 IoC 容器用到了系统中。不过他也很坑,他写的 IoC 容器出了问题,根本找不到任何解决资料,只能看源码。自己写的只能做玩具玩玩吧。
Spring OAuth2 GitHub 自定义登录信息的更多相关文章
- DedeCMS中实现在顶层banner中显示自定义登录信息
一.需求描述 dedeCMS自带的模板中有互动中心模块,如下图所示: 由于会员登陆对我来说不是网站的重要模块且默认DedeCMS的会员中心模块的初始化很慢,常会显示“正在载入中,请稍候...”, 所以 ...
- spring oauth2获取当前登录用户信息。
使用spring oauth2框架做授权鉴定.想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的. spring security可以通过Sec ...
- spring security使用自定义登录界面后,不能返回到之前的请求界面的问题
昨天因为集成spring security oauth2,所以对之前spring security的配置进行了一些修改,然后就导致登录后不能正确跳转回被拦截的页面,而是返回到localhost根目录. ...
- spring security采用自定义登录页和退出功能
更新... 首先采用的是XML配置方式,请先查看 初识Spring security-添加security 在之前的示例中进行代码修改 项目结构如下: 一.修改spring-security.xml ...
- Spring Security 自定义登录页面
SpringMVC + Spring Security,自定义登录页面登录验证 学习参考:http://www.mkyong.com/spring-security/spring-security-f ...
- SpringCloud微服务实战——搭建企业级开发框架(四十):使用Spring Security OAuth2实现单点登录(SSO)系统
一.单点登录SSO介绍 目前每家企业或者平台都存在不止一套系统,由于历史原因每套系统采购于不同厂商,所以系统间都是相互独立的,都有自己的用户鉴权认证体系,当用户进行登录系统时,不得不记住每套系统的 ...
- 【SpringSecurityOAuth2】源码分析@EnableOAuth2Sso在Spring Security OAuth2 SSO单点登录场景下的作用
目录 一.从Spring Security OAuth2官方文档了解@EnableOAuth2Sso作用 二.源码分析@EnableOAuth2Sso作用 @EnableOAuth2Client OA ...
- Spring Security笔记:自定义登录页
以下内容参考了 http://www.mkyong.com/spring-security/spring-security-form-login-example/ 接上回,在前面的Hello Worl ...
- Spring Security入门(2-3)Spring Security 的运行原理 4 - 自定义登录方法和页面
参考链接,多谢作者: http://blog.csdn.net/lee353086/article/details/52586916 http元素下的form-login元素是用来定义表单登录信息的. ...
随机推荐
- JavaScript将小写金额转换成大写
//num为小写金额,单位元 changeMoney(num) { if(isNaN(num))return ""; var strPrefix=""; if( ...
- shell脚本中 杀死可能成为僵尸进程的方法
交互式 Bash Shell 获取进程 pid 在已知进程名(name)的前提下,交互式 Shell 获取进程 pid 有很多种方法,典型的通过 grep 获取 pid 的方法为(这里添加 -v gr ...
- 模板语言变量,js变量,js自执行函数之前嵌套调用
1.模板语言变量 前端html页面中展示 {{ nodeIp }} 2.js变量引用模板语言变量 把模板语言变量传递给js,js去执行页面操作(变量的转换,只适用于字符串) var IP = &quo ...
- JMeter使用(Linux)
JMeter是一个Java桌面应用程序,用户界面采用Swing Java Api实现,支持并发和多线程或者线程组的执行,对于配置负载测试和压力测试非常有用.Jmeter是开源.免安装的,只需要有jdk ...
- datanode启动不起来的各种原因
一般在数据节点的log日志信息里能找到导致启动不起来的原因. 1.Namenode和Datanode的NamenodeID不一致 描述:一般在集群多次重新格式化HDFS之后,或者刚安装时会碰到.日志信 ...
- linux系统/sbin/init执行过程
对于Linux的启动过程,之前一直都是研究到内核运行/sbin/init,启动第一个用户进程为止,因为这部分一直都是在内核态工作,所以对于学习内核还是有帮助的,当时/sbin/init之后的过程也需要 ...
- tomcat证书配置
第一步:为服务器生成证书 1.进入%JAVA_HOME%/bin目录 2.使用keytool为Tomcat生成证书,假定目标机器的域名是"localhost",keystore文件 ...
- 非空校验的提示按钮(shiro项目中来的六)
一:图示 二,js脚本 /** * jquery tips 提示插件 jquery.tips.js v0.1beta * * 使用方法 * $(selector).tips({ //selector ...
- 【原】从零开始改造淘淘商城(引入dubbo解决项目耦合)02
前言: 关于为什么要引入dubbo框架,而不是用spring cloud或者是motan呢,主要是笔者现在公司用的就是dubbo,并且第一次接触到微服务的概念是来源于dubbo,再加上最近dubbo频 ...
- 【原】spring boot添加cros全局过滤器
新增一个过滤器类并实现filter接口 public class CorsFilter implements Filter { final static org.slf4j.Logger logger ...