自定义认证逻辑
写在前面在前面我们对SpringSecurity中的登录流程进行了较为详细的分析,但是采用的都是系统默认的认证逻辑,这种方式在学习中尚能使用,但是在实际工作中一般都会自定义登录逻辑。笔者结合自己实际工作中的一些应用来介绍一种比较常用的自定义认证逻辑。
知识回顾前面我们在《添加登录验证码》和《前后端分离JSON格式登录实现》两篇文章中,通过自定义过滤器,并在过滤器中实现了相应的逻辑,这些也是自定义认证逻辑的范畴,只不过是最为基础罢了,但是它们都存在一些问题,如下面的例子所述的那样。
假设现在有一个系统,我们给它添加了一个验证码,同时为了校验验证码,需要自定义一个过滤器,并将该过滤器放入SpringSecurity的过滤器链中,之后每次请求都会通过该过滤器。这样的逻辑看似没有问题,但是你仔细想就会发现,我们仅仅需要登录的请求经过该过滤器,其他请求是无需经过的,因此如果你对性能有较为严苛的要求,那么就有必要对上述逻辑进行修改。
认证流程分析首先阅读《详解登录流程》一文,之后再来阅读本部分内容会容易很多。
通过查阅ProviderManager#authenticate()方法中的源码可以知道 ...
令牌持久化和二次验证
写在前面前一篇学习了如何实现自动登录,但是随之而来的是以牺牲系统安全为代价,这一点在很多场景下都是不可取的,因此就必须对自动登录的核心—令牌进行一些安全提升,或者采用二次验证等方式来提升系统的安全性。
令牌持久化概念前面提到过一个makeTokenSignature()方法,该方法的逻辑是计算令牌过期时间、用户名、密码和盐Key参数所构成字符串的哈希值:
12345678910protected String makeTokenSignature(long tokenExpiryTime, String username, String password) { String data = username + ":" + tokenExpiryTime + ":" + password + ":" + this.getKey(); try { MessageDigest digest = MessageDigest.getInstance("MD5 ...
实现自动登录
写在前面在前面对登录流程进行了较为细致的学习之后,接下来实现一个常用的功能—自动登录。请注意本篇新建了一个工程auto-login,不再使用之前的代码。
使用场景以常用的QQ邮箱为例,如下所示界面就是支持自动登录:
不仅仅是这里举例的QQ邮箱,很多网站都有这个功能。对于用户来说,每次登录都需要输出用户名和密码不仅增加了登录难度,降低用户体验,更重要的是账号被盗的风险也随之提升。
自动登录,说白了就是用户在登录成功后,那么在接下来的一段时间里,就算发生了诸如用户关闭浏览器、服务器宕机重启等行为时,此时用户依旧可以保持之前的登录状态,而不用重新登录。SpringSecurity对于自动登录提供了简易的配置方式,开发者通过简单的一些配置就能实现较为复杂的自动登录功能。
工程初始化第一步,使用IDEA创建一个名为auto-login的SpringBoot工程,之后选择添加Web和SpringSecurity依赖。
第二步,在application.yml配置文件中新增如下配置信息,用于自定义登录用户名和密码:
12345spring: security: user: nam ...
填坑,前后端分离JSON格式登录实现
写在前面如果你之前阅读过笔者写过的《前后端分离回调和注销登录》和《添加登录验证码》两篇文章,会发现一个比较尴尬的事情,当时我们说好是采用前后端分离模式,前后端之间以JOSN格式的数据进行传输,但是在用户登录的时候,我们其实并没有采用JSON格式,依旧使用了Key/Value键值对形式。除此之外,其余所有的POST请求都采用了JSON格式,这是当时笔者偷了一个懒所导致的。原因在于SpringSecurity中默认的登录数据格式就是Key/Value键值对形式,因此我就直接使用了,没做修改,但是在实际工作中有必要进行全部统一,因此本篇就来将其进行改造,使之也采用JSON格式来传输数据。
现有方式通过《详解登录流程》一文,我们知道用户登录信息是在UsernamePasswordAuthenticationFilter类中处理的,里面有三个重要的方法:
123456789101112131415161718192021222324public Authentication attemptAuthentication(HttpServletRequest request, HttpServlet ...
添加登录验证码
写在前面在前一篇《详解登录流程》一文中,笔者提到当开发者需要在SpringSecurity中自定义一个登录验证码或者将登录参数修改为JSON时,都需要自定义自己的Filter类,并继承这个AbstractAuthenticationProcessingFilter类,那么接下来的两篇就分别介绍如何自定义登录验证码和将登录参数修改为JSON格式。
本文是在之前的security-jpa项目上进行修改的。
生成验证码既然想在SpringSecurity中使用验证码,那么首先是生成验证码,这里采用Java来生成验证码。
新建一个utils包,并在里面新建一个生成验证码的工具类VerifyCode,里面的代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 ...
详解登录流程
写在前面在前面学习前后端分离模式下的回调和注销时,提到了密码擦除,当时没有对SpringSecurity的登录流程进行梳理,那么本篇就来详细学习登录流程。
场景描述现在有一个场景,用户在服务端安全管理选择了SpringSecurity,那么用户登录成功后,SpringSecurity会将用户信息保存在Session中,但是具体保存的位置,就目前而言开发者是不知道的,但是现在就是想知道这个信息的保存位置,以便当用户在前端修改了自己的信息,在不重新登录的情况下,开发者如何获取到用户的最新信息?这个场景在实际工作中是很常见的。
Authentication对象如果你之前使用过Shiro框架,那么就知道在Shiro框架中与用户认证相关的信息都在AuthenticationToken接口中,查看一下这个接口的源码:
12345public interface AuthenticationToken extends Serializable { Object getPrincipal(); Object getCredentials();}
它只有两个方法,一个获取 ...
Spring Data JPA操作数据库
写在前面在前一篇我们学习了如何基于数据库来实现授权操作,使用了JdbcUserDetailsManager类,同时发现它底层使用的是JdbcTemplate,用户操作非常不方便,且使用了JdbcUserDetailsManager自带的数据库,这些表和字段是无法满足实际的开发需要,因此通常做法是开发者自定义授权数据库和表。
出于操作简单的考虑,这里使用Spring Data JPA来代替JdbcTemplate进而完成对数据库的操作。
创建工程使用IDEA创建一个名为security-jpa的SpringBoot工程:
当然也可以在创建项目的时候不添加任何依赖,而是在后续pom.xml依赖文件中添加如下依赖:
12345678910111213141516171819202122232425262728293031323334<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
基于数据库的授权操作
写在前面前面学习的都是基于内存的授权操作,但是在实际开发过程中都是将数据存储在数据库中,因此本篇就来学习如何基于数据库来实现授权操作。
UserDetailService接口通过前面的学习,我们知道SpringSecurity存在多种认证方式,查看一下这个AuthenticationManagerBuilder类,可以发现它存在inMemoryAuthentication(内存)、jdbcAuthentication(数据库)和ldapAuthentication(LDAP)等三种认证方式:
1234567891011public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication() throws Exception { return (InMemoryUserDetailsManagerConfigurer)this.apply(new InMemoryUserDetailsManagerConfigurer());} ...
基于内存的授权操作
写在前面本篇来学习Spring Security中的授权操作,建议先阅读之前Shiro框架相关的几篇内容,通过对比学习可以加深对授权的理解。
授权授权就是当用户通过认证之后,需要访问某一资源的时候,我们需要检查用户是否具备访问该资源的权限,如果具备就允许访问;反之则不允许。
认证我们知道用户想要进行授权,前提是已经通过了认证,而SpringSecurity存在多种认证方式,查看一下这个AuthenticationManagerBuilder类,可以发现它存在inMemoryAuthentication(内存)、jdbcAuthentication(数据库)和ldapAuthentication(LDAP)等三种认证方式:
1234567891011public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication() throws Exception { return (InMemoryUserDetailsManagerConfig ...
前后端分离回调和注销登录
在前一篇学习了前后端不分离模式下的登录回调和注销登录,接下来开始学习前后端分离模式下的登录回调和注销登录。请注意,前后端分离模式下,前后端是通过json来进行数据交互,因此和之前需要采用不同的处理方式。还有前后端分离模式下认证是使用传统的session还是采用像JWT一样的token呢?这些同样需要引起注意。
状态传统方式是通过session来记录用户认证信息,可以理解为是一种无状态登录,而JWT则是一种无状态登录,那么有状态和无状态的区别是什么?在此之前需要了解http无状态以及最好知道cookie、session和token这三者之间的区别。
http无状态http协议是无状态的,这里的无状态协议是指协议对于事务处理没有记忆能力。缺少状态,说明一旦数据交换完毕,客户端与服务器之间的连接就会关闭,若想再次进行数据交换则需建立新的连接,这就意味着服务器无法从连接上跟踪会话。
会话跟踪会话,指用户登录网站后的一系列动作,如浏览商品、添加商品至购物车、购买商品等。会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie和Session,其 ...