# 相关代码

https://github.com/mofadeyunduo/money

0.1.3-SNAPSHOT

security 模块中

# 原因

最近在做一款管理金钱的网站进行自娱自乐,发现没有安全控制岂不是大家都知道我的工资了(一脸黑线)?

最近公司也在搞 Spring OAuth2,当时我没有时间(其实那时候不想搞)就没做,现在回头来学习学习。

Spring OAuth2 官方的教程写的比较少,实用性比较差。

# 教程内容

  1. Spring OAuth2 Github SSO
  2. 替换认证过的 Spring Security Authentication 对象
  3. 后端设置 Cookie 实现 Remember-Me 功能

# Github 登录

Spring OAuth2 Github,官网写的已经比较详细了。

要注意的是必须要配置两个 Filter:

  • OAuth2ClientAuthenticationProcessingFilter ,用于处理 OAuth2 流程。
  • OAuth2ClientContextFilter,用于触发跳转到 OAuth2 请求。

P.S. 这很诡异,我不知道 Spring OAuth2 为什么要这么做。

# 替换认证过的 Spring Security Authentication

步骤:

  1. 重写方法 getPrincipal,把 Authentication 中的 Principal 换成用户信息对象。
  2. 最好设置 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

  1. 实现 UserDetailServices。
  2. 用 UserDetailServices 构造 RememberMeServices。这里采用的 RememberMeServices 的具体实现是 TokenBasedRememberMeServices。TokenBasedRememberMeServices 会用 UserDetailServices 构造 Authentication 的 Principal 对象。还有一个构造参数(key)是指定盐,指定一个值,该值在应用反复重启的时要保持不变。顺便提一下,TokenBasedRememberMeServices 加密是根据 UserDetailServices 构造出的 UserDetails 中的 username、password、时间戳、构造参数 key 进行 MD5 和 Base64 加密和解密。
  3. 在 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 自定义登录信息的更多相关文章

  1. DedeCMS中实现在顶层banner中显示自定义登录信息

    一.需求描述 dedeCMS自带的模板中有互动中心模块,如下图所示: 由于会员登陆对我来说不是网站的重要模块且默认DedeCMS的会员中心模块的初始化很慢,常会显示“正在载入中,请稍候...”, 所以 ...

  2. spring oauth2获取当前登录用户信息。

    使用spring oauth2框架做授权鉴定.想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的. spring security可以通过Sec ...

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

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

  4. spring security采用自定义登录页和退出功能

    更新... 首先采用的是XML配置方式,请先查看  初识Spring security-添加security 在之前的示例中进行代码修改 项目结构如下: 一.修改spring-security.xml ...

  5. Spring Security 自定义登录页面

    SpringMVC + Spring Security,自定义登录页面登录验证 学习参考:http://www.mkyong.com/spring-security/spring-security-f ...

  6. SpringCloud微服务实战——搭建企业级开发框架(四十):使用Spring Security OAuth2实现单点登录(SSO)系统

    一.单点登录SSO介绍   目前每家企业或者平台都存在不止一套系统,由于历史原因每套系统采购于不同厂商,所以系统间都是相互独立的,都有自己的用户鉴权认证体系,当用户进行登录系统时,不得不记住每套系统的 ...

  7. 【SpringSecurityOAuth2】源码分析@EnableOAuth2Sso在Spring Security OAuth2 SSO单点登录场景下的作用

    目录 一.从Spring Security OAuth2官方文档了解@EnableOAuth2Sso作用 二.源码分析@EnableOAuth2Sso作用 @EnableOAuth2Client OA ...

  8. Spring Security笔记:自定义登录页

    以下内容参考了 http://www.mkyong.com/spring-security/spring-security-form-login-example/ 接上回,在前面的Hello Worl ...

  9. Spring Security入门(2-3)Spring Security 的运行原理 4 - 自定义登录方法和页面

    参考链接,多谢作者: http://blog.csdn.net/lee353086/article/details/52586916 http元素下的form-login元素是用来定义表单登录信息的. ...

随机推荐

  1. 如何解决使用Gradle时出现的jar包冲突

    前言 在我之前使用Gradle的博文中已经提到,Gradle对依赖的管理是比较智能的,如果有两个包依赖于相同的包,而版本不同的时候,Gradle会进行自动的选择,从而避免jar包的冲突. 也就是说,在 ...

  2. Phpstrom操作Git从服务器端克隆代码到本地

    1.第一步点开Git 2.添加项目的路径 第一个框是你所在的项目路径,后缀名是.git,这里我用的是HTTPS的方式(还有一种是SSH) 第二是你要克隆到所在目录,我的是在Apache下面的htdoc ...

  3. yum仓库详细解读

    Yum:Yellowdog Updater,Modified的简称,起初由yellow dog发行版的开发者Terra Soft研发,用Python编写,后经杜克大学的Linux@Duke开发团队进行 ...

  4. CSS盒模型的深度思考及BFC

    本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. 题目:谈一谈你对CSS盒模型的认识 专业的面试,一定会问 CSS 盒模型 ...

  5. 【前端】Angular2 Ionic2 学习记录

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/angular2_ionic2.html 一.建立项目 ionic start ProductName super ...

  6. 重磅︱文本挖掘深度学习之word2vec的R语言实现

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 笔者寄语:2013年末,Google发布的 w ...

  7. 慢慢来写SpringMVC基本项目

    首先新建一个maven项目. 这里选用webapp的.在点击next弹出的界面的groupID和artifactID自己定义憋.好了,这个第一步完成.创建完可能会有个红叉在项目上, 这个只需要在pom ...

  8. ClientToScreen 和ScreenToClient 用法

    ClientToScreen( )是把窗口坐标转换为屏幕坐标 ScreenToClient( )是把屏幕坐标转换为窗口坐标 屏幕坐标是相对于屏幕左上角的,而窗口坐标是相对于窗口用户区左上角的 VC下, ...

  9. HighCharts之2D半圆环图

    HighCharts之2D半圆环图 1.实例源码 HalfDonut.html: <!DOCTYPE html> <html> <head> <meta ch ...

  10. Error: expected expression, got '}'

    1.错误描述 Error: expected expression, got '}' .globalEval/<@http://localhost:8080/Sys/resource/globa ...