一个完整的授权码模式实例
写在前面前面我们对OAuth2.0中四种授权模式进行了学习,接下来将通过一个完整的实例来研究授权码模式,深入理解其中的各个流程。
实例架构授权码模式是功能最完整、流程最严谨的授权模式。它的特点就是通过客户端的服务器与授权服务器进行交互,涉及到资源所有者(用户)、客户端(第三方应用)、授权服务器和资源服务器这四个角色。由于用户就是笔者,因此无需提供项目实例,而其他三者这里就提供各自的项目实例,各实例项目名称、角色名称和端口如下表所示:
项目名称
角色名称
端口
auth-server
授权服务器
8080
user-server
资源服务器
8081
client-app
客户端(第三方应用)
8082
空Maven父工程搭建使用Maven新建一个空白的父工程,名称为authorization-code,之后我们将在这个父工程中搭建子项目。
授权服务器搭建在authorization-code父工程中新建一个子模块,名称为auth-server,在选择依赖的时候选择如下三个依赖:Web、Spring Cloud Security和Spring Cloud OAut ...
OAuth2.0四种授权模式
写在前面在《OAuth2.0的一个简单解释》一文中,我们对OAuth2.0的含义和设计思想有了一个较为清晰的认识,那么接下来就学习OAuth2.0中的四种授权模式。
OAuth2角色在学习授权模式之前,了解OAuth2中的4种基本角色对于学习和理解OAuth的工作原理有重要意义。(1)资源所有者:资源所有者即用户,具有头像、照片、视频等资源;(2)客户端:客户端即第三方应用,如前一篇中提到的知乎;(3)授权服务器:授权服务器用来验证用户提供的信息是否正确,并返回一个令牌给第三方应用;(4)资源服务器:资源服务器是提供给用户资源的服务器,如头像、照片、视频等资源。
通常来说,授权服务器和资源服务器可以是同一台服务器。
OAuth2授权流程在熟悉了OAuth2中的4个基本角色以后,接下来开始学习OAuth2的授权流程,具体的流程如下:(1)客户端(第三方应用)向用户请求授权;(2)用户单击客户端所呈现的服务授权页面上的同意授权按钮后,服务端返回一个授权许可凭证给客户端;(3)客户端拿着授权许可凭证去授权服务器申请令牌;(4)授权服务器验证信息无误后,发放令牌给客户端;(5)客户端拿着令牌去 ...
OAuth2.0的一个简单解释
写在前面乘着年尾还有点时间,打算将今年学到的OAth2相关知识进行总结,一来是便于自己对知识点的汇总,二来是怕自己遗忘,写几篇笔记来进行记录。
OAth2快递员问题一开始我也不太明白OAth2这个概念,直到某一天看到阮一峰写的OAth2博客,才对OAth2有了一个更为清晰的理解和认识。他通过一个快递员问题,从身边的事物入手,来理解OAth2的概念。
假设笔者住在一个大型的居民小区,小区有门禁系统,任何人进入的时候需要输入密码。笔者非常喜欢淘货,每天都有快递员来送货,因此笔者必须找到一个办法,让快递员通过门禁系统,进入小区进而给我派件。现在问题来了,如果我把我的密码告诉快递员,那么快递员就拥有了和我一样的权限,这似乎不太合适。还有万一我修改了密码,那我必须告诉所有的快递员,这样它们才能继续进入小区。
那么问题来了,有没有一种办法可以让快递员既可以自由的进出小区,又无需知道小区居民的用户密码,而且他唯一的权限就是派件,其他需要密码的场合,他都不能进,没有对应的权限。
授权机制的设计针对上述问题,笔者设计了一套授权机制。
第一步,在门禁系统的密码输入器下面增加一个按钮,叫做”获取授权”。快递 ...
集群环境下SpringSecurity处理Session
写在前面通过前面《内存保存用户+自动踢掉登录用户》、《传统方式+JPA+自动踢掉登录用户》、《前后端分离+JPA+自动踢掉登录用户》三篇的学习,我们已经对SpringSecurity中如何自动踢掉已登录用户有了较为清晰的认识,不过前面学习的都是基于单体应用,当项目是集群化部署时,上述配置还能使用么?如果不能使用,那么应该采用什么方式呢?带着这些问题我们来进入本篇的学习。
注意本篇使用的操作系统为Windows,所涉及到的Redis和Nginx均是在Windows上面部署的。
集群会话方案在传统的单体服务架构中,通常只有一台服务器,因此就不存在Session共享问题。但是在分布式或者集群项目中,Session共享是一个必须面对的问题。
下面是一个简单的集群项目架构图:
从图中可以知道,当客户端发起一个请求,此时请求到达Nginx上,被Nginx转发到TomcatA上,之后TomcatA往Session中保存了一份数据,之后客户端又发起一次请求,但是这个请求被Nginx转发到TomcatB上,由于TomcatB中不存在之前的Session信息,因此无法从中获取数据。
这个现象在分布式或者 ...
防御固定会话攻击
写在前面在前面《自动踢掉登录用户》一文中,我们通过使用SpringSecurity中的Session并发控制实现了像QQ一样的功能,即当用户在一台设备上登录成功,之后会自动踢掉另一台设备上的已登录。
其实SpringSecurity中的Session功能非常强大,本篇要学的就是是什么是会话固定攻击以及SpringSecurity中如何防御会话固定攻击,此时就需要使用到Session。
项目实例化第一步,使用IDEA创建一个名为fixation-attack的SpringBoot工程,并在其pom.xml依赖文件中添加如下依赖:
123456789101112131415161718192021<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ...
自带防火墙学习
写在前面前面我们对SpringSecurity中用户登录相关内容进行了深度学习,接下来开始学习SpringSecurity自带的防火墙,了解和使用防火墙对于提升系统的安全性有重要帮助。
杂谈在学习SpringSecurity之前,我们对Shiro框架进行了学习,发现它非常轻量,没有这么复杂的功能和配置。同时随着对SpringSecurity框架的深度学习,我们发现它底层其实用的还是Servlet的那套东西?就前面所述的自动踢掉登录用户这一功能来说,开发者完全可以自定义一个Filter来实现请求拦截,而且逻辑和配置非常简单。
尽管是可以这么操作,但是笔者不建议大家这样操作,因为我们自定义Filter可能仅仅是为了让认证和授权等功能变得简单,但是却忽略了安全等问题,显然安全必须是首要考虑的。
其实各种各样的Web攻击每天都在发生,可能你感知不到,那是因为有系统在保护着,小到系统本身自带的攻击防御,大到公司的防火墙。如果你自定义了Filter,那么你就需要针对不同的攻击,书写对应的代码来防护,毫无疑问,这就要求开发者不仅对一些常见的Web攻击,如固定会话攻击,CSRF攻击等有较为详细的了解, ...
前后端分离+JPA+自动踢掉登录用户
写在前面在前一篇《自动踢掉登录用户》一文中,我们采用的是前后端不分离模式,但是在前后端分离盛行的当下,有必要对此模式下的自动踢掉用户进行学习。同时在前一文中,用户信息都是配置在内存中,而实际工作中都是将其放入数据库中,因此需要切换数据源为数据库。需要注意的是,在使用SpringSecurity中的Session做并发处理时,直接将内存中的用户切换为数据库中的用户,也就是将内存源切换为数据库源是会出现问题的,接下来就来细说这个问题。
前后端分离项目实例化考虑到此处主要学习如何在前后端分离模式下,实现自动踢掉登录用户,因此就只是单纯的将用户存储在数据库中,而不进行任何的权限控制。同时此处登录使用JSON格式。
第一步,使用IDEA创建一个名为kickoffuser-json的SpringBoot工程,并在其pom.xml依赖文件中添加如下依赖:
12345678910111213141516171819202122232425262728293031323334<dependencies> <dependency> <groupId> ...
传统方式+JPA+自动踢掉登录用户
写在前面在《自动踢掉登录用户》一文中,出于简单考率,我们将用户信息保存在内存中,但是在实际工作中都是将用户信息保存早数据库中。看到这里,小伙伴是不是觉得只需将数据库保存用户替换为内存保存用户,完全没必要新开一篇文章,是的通常都是可以直接这么操作,但是这里仅仅这么操作是不行的,因此此处有必要单独进行介绍。
项目初始化考虑到此处主要学习如何在前后端不分离模式下,实现自动踢掉登录用户,因此就只是单纯的将用户存储在数据库中,而不进行任何的权限控制。
第一步,使用IDEA创建一个名为kickoffuser-jpa的SpringBoot工程,并在其pom.xml依赖文件中添加如下依赖:
12345678910111213141516171819202122232425262728293031323334<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter ...
内存保存用户+自动踢掉登录用户
写在前面经过前面的学习,我们已经对SpringSecurity用户登录内容有了较为深刻的认识,接下来学习一个较为有意思的功能—自动踢掉登录用户。
你可能不知道什么是“自动踢掉登录用户”,但是你可能遇到过这种场景:当你在A电脑上登录了QQ,然后再在B电脑上登录时,QQ就会将你从A电脑上踢下线,也就是告知你同一时刻同一平台你只能登录一个实例。
从本篇文章开始,如果没有特殊说明,那么都是新建一个gitee分支,在新的项目上进行编码。在gitee上新建一个kickoff-user分支,然后将本地分支切换过去,接下来开始进行代码逻辑编写。
需求描述在实际工作中,出于安全考量,我们可能要求某个系统只允许一个用户在一个终端上登录,更有甚者要求一个用户在一个设备上登录。如钉钉,这款软件就规定用户最多只能在三台手机上登录(仅仅针对手机端),显然这就是对用户登录的设备进行了绑定。
需要说明的是,终端和设备两者是不同的,终端包括PC、手机端等方式,而设备就是指单纯的某台具体的手机。
要实现上述功能,即一个用户无法同时在两台设备上登录,可以有两种实现思路:(1)后来的登录用户踢掉前面已经登录的用户,QQ就是这 ...
获取登录额外信息
写在前面通过前面《详解登录流程》一文的学习,我们已经对用户登录流程、认证过程和保存用户信息等内容有了一个较为清晰的认识。同时我们也对用户登录流程和认证过程分别用了更为详细的内容去进行学习,那么本篇就花点时间来学习关于保存用户信息等那些事。
Authentication对象首先阅读《详解登录流程》一文,之后再来阅读本部分内容会容易很多。
前面我们曾多次提到过Authentication这个接口,它用来保存用户的登录信息,这里再次贴上该接口的源码:
12345678910111213public interface Authentication extends Principal, Serializable { Collection<? extends GrantedAuthority> getAuthorities(); Object getCredentials(); Object getDetails(); Object getPrincipal(); boolean isAuthenticated(); void setAu ...