Day238,分享面经,超过500人面试阿里

2.1 用户量

Shiro的使用量一直高于spring security。但是从趋势上来看(2020年10月的百度指数),Spring Security是在一直上升的,shiro的使用量同比、环比都进入了下滑期。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3FkOTI6-1617534829662)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403191135.png)]


2.2.使用的方便程度

通常来说,shiro入门更加容易,使用起来也非常简单,这也是造成shiro的使用量一直高于Spring Security的主要原因。但是从笔者的角度来看,二者其实都简单,我说说我的理由:

  • 在没有Spring Boot之前,Spring Security的大部分配置要通过XML实现,配置还是还是非常复杂的。但是有了 Spring Boot之后,这一情况已经得到显著改善。

  • Spring Security之所以看上去比shiro更复杂,其实是因为它引入了一些不常用的概念与规则。大家应该都知道2/8法则,这在Spring Security里面体现的特别明显,如果你只学Spring Security最重要的那20%,这20%的复杂度和shiro基本是一致的。也就是说,不重要的那80%,恰恰是Spring Security比shiro的“复杂度”。

也就是说,如果有人能帮你把Spring Security最重要的那20%摘出来,二者的入门门槛、复杂度其实是差不太多的。

2.3.社区支持

Spring Security依托于Spring庞大的社区支持,这点自不必多说。shiro属于apache社区,因为它的广泛使用,文档也非常的全面。二者从社区支持来看,几乎不相上下。

但是从社区发展的角度看,Spring Security明显更占优势,随着Spring Cloud、Spring Boot、Spring Social的长足进步,这种优势会越来越大。因为Spring Security毕竟是Spring的亲儿子,Spring Security未来在于Spring系列框架集成的时候一定会有更好的融合性,前瞻性、兼容性!这也是为什么我们要学Spring Security的主要原因!

2.4.功能丰富性

Spring Security因为它的复杂,所以从功能的丰富性的角度更胜一筹。其中比较典型的如:

  • Spring Security默认含有对OAuth2.0的支持,与Spring Social一起使用完成社交媒体登录也比较方便。shiro在这方面只能靠自己写代码实现。

  • 还有一种普遍说法:Spring Security在网络安全的方面下的功夫更多,但是笔者并未有非常直接的感受,有可能出现安全问题的时候才会感到不够安全的痛。


三、总结


如果你只是想实现一个简单的web应用,shiro更加的轻量级,学习成本也更低。如果您正在开发一个分布式的、微服务的、或者与Spring Cloud系列框架深度集成的项目,笔者还是建议您使用Spring Security。


2、需求分析与基础环境准备

=======================================================================

一、需求分析


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UGMRSd3A-1617534829665)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403192317.png)]

  • login.html登录页面,登录页面访问不受限制

  • 在登录页面登录之后,进入index.html首页(登录验证Authentication)

  • 首页可以看到syslog、sysuer、biz1、biz2四个页面选项

  • 我们希望syslog(日志管理)和sysuser(用户管理)只有admin管理员可以访问(权限管理Authorization)

  • biz1、biz2普通的操作普通用户登录即可访问(权限管理Authorization)

其中 login.html是html文件,其他文件是以.html为后缀的freemarker模板文件

我们先将以上页面准备好,先不做任何访问权限上的限制!以上需求我们将在后面章节实现

二、环境准备


  1. 起一个新的spring boot2.x 版本的web应用

  2. 集成lombok、mybatis、log4j等

  3. 集成一个前端模板,我这里使用的是freemarker。你可以根据自己需要整合jsp、thymeleaf等都可以。

为了让课程尽量的干一点,因为这套课程主要是讲security及web应用安全,所以不会花时间在spring boot整合开源软件,及增删改查怎么写!如果不知道怎么做。可以参考:https://www.kancloud.cn/hanxt/springboot2/content 网上也有很多的资料。

如果你实在不愿意自己集成,下面的是我整合之后的结果,可以直接使用。该项目只用于项目初始化,不包含后面课程的源代码。

https://gitee.com/hanxt/boot-security-starter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5qxGqV7-1617534829670)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403193513.png)]

注意login.html页面的存放位置和其他文件的存放位置不一样。public文件夹里面的html文件可以对外公开访问

  • login.html
首页

阿昌业务系统登录

用户名称

用户密码

  • index.html
阿昌业务管理系统

阿昌业务管理系统


日志管理


用户管理


具体业务一


具体业务二

  • application.yml

server:

port: 8888

spring:

datasource:

url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false

username: root

password: 00000

driver-class-name: com.mysql.cj.jdbc.Driver

freemarker:

cache: false # 缓存配置 开发阶段应该配置为false 因为经常会改

suffix: .html # 模版后缀名 默认为ftl

charset: UTF-8 # 文件编码

template-loader-path: classpath:/templates/ # 模版的路径地址

  • BizpageController

@Controller

public class BizpageController {

// 登录

@PostMapping(“/login”)

public String index(String username,String password) {

return “index”;

}

// 日志管理

@GetMapping(“/syslog”)

public String showOrder() {

return “syslog”;

}

// 用户管理

@GetMapping(“/sysuser”)

public String addOrder() {

return “sysuser”;

}

// 具体业务一

@GetMapping(“/biz1”)

public String updateOrder() {

return “biz1”;

}

// 具体业务二

@GetMapping(“/biz2”)

public String deleteOrder() {

return “biz2”;

}

}

syslog.html、sysuser.html、biz1.html、biz2.html内容随便写点,能够方便做内容上的彼此区分即可。


3、HttpBasic模式登录认证

===========================================================================

一、HttpBasic模式的应用场景


HttpBasic登录验证模式是Spring Security实现登录验证最简单的一种方式,也可以说是最简陋的一种方式。它的目的并不是保障登录验证的绝对安全,而是提供一种“防君子不防小人”的登录验证。

就好像是我小时候写日记,都买一个带小锁头的日记本,实际上这个小锁头有什么用呢?如果真正想看的人用一根钉子都能撬开。它的作用就是:某天你的父母想偷看你的日记,拿出来一看还带把锁,那就算了吧,怪麻烦的。

举一个我使用HttpBasic模式的进行登录验证的例子:我曾经在一个公司担任部门经理期间,开发了一套用于统计效率、分享知识、生成代码、导出报表的Http接口。纯粹是为了工作中提高效率,同时我又有一点点小私心,毕竟各部之间是有竞争的,所以我给这套接口加上了HttpBasic验证。公司里随便一个技术人员,最多只要给上一两个小时,就可以把这个验证破解了。说白了,这个工具的数据不那么重要,加一道锁的目的就是不让它成为公开数据。如果有心人破解了,真想看看这里面的数据,其实也无妨。这就是HttpBasic模式的典型应用场景。

二、spring boot2.0整合Spring security


spring boot 2,x版本maven方式引入Spring security坐标。

org.springframework.boot

spring-boot-starter-security

三、HttpBasic登录认证模式


如果使用的Spring Boot版本为1.X版本,依赖的Security 4.X版本,那么就无需任何配置,启动项目访问则会弹出默认的httpbasic认证.

我们现在使用的是spring boot2.0版本(依赖Security 5.X版本),HttpBasic不再是默认的验证模式,在spring security 5.x默认的验证模式已经是表单模式。所以我们要使用Basic模式,需要自己调整一下。并且security.basic.enabled已经过时了,所以我们需要自己去编码实现。

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

//进行安全认证及授权规则配置

@Override

protected void configure(HttpSecurity http) throws Exception {

http.httpBasic()//开启httpbasic认证

.and()

.authorizeRequests()//表示所有的请求

.anyRequest()//匹配规则是所有请求

.authenticated();//都需要登录认证

//上面的一顿操作为:所有请求都必须经过springsecurity过滤器链登录认证才能访问,认证模式是httpbasic

}

}

启动项目,在项目后台有这样的一串日志打印,冒号后面的就是默认密码。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G6H1r8U6-1617534829676)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403200702.png)]

Using generated security password: d707345c-4d1e-461c-bfe0-865297f8fb11

我们可以通过浏览器进行登录验证,默认的用户名是user.(下面的登录框不是我们开发的,是HttpBasic模式自带的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LHMhRymu-1617534829678)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403200839.png)]

当然我们也可以通过application.yml指定配置用户名密码

spring:

security:

user:

name: admin

password: admin


四、HttpBasic模式的原理说明


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BkqUDDC1-1617534829681)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403201549.png)]

  • 首先,HttpBasic模式要求传输的用户名密码使用Base64模式进行加密。如果用户名是 "admin" ,密码是“ admin”,则将字符串"admin:admin"使用Base64编码算法加密。加密结果可能是:YWtaW46YWRtaW4=。

  • 然后,在Http请求中使用Authorization作为一个Header,“Basic YWtaW46YWRtaW4=“作为Header的值,发送给服务端。(注意这里使用Basic+空格+加密串)

  • 服务器在收到这样的请求时,到达BasicAuthenticationFilter过滤器,将提取“ Authorization”的Header值,并使用用于验证用户身份的相同算法Base64进行解码。

  • 解码结果与登录验证的用户名密码匹配,匹配成功则可以继续过滤器后续的访问。

所以,HttpBasic模式真的是非常简单又简陋的验证模式,Base64的加密算法是可逆的,你知道上面的原理,分分钟就破解掉。我们完全可以使用PostMan工具,发送Http请求进行登录验证。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKaG8yHF-1617534829683)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403201606.png)]

  • 直接拿去base64解密

账号密码直接生成出来!!!!!!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w298cQlx-1617534829685)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403202126.png)]


4、PasswordEncoder介绍

=============================================================================

一、Hash算法加密


Hash算法特别的地方在于它是一种单向算法,用户可以通过hash算法对某个数据生成一段特定长度的唯一hash值,却不能通过这个hash值逆向获取原始数据。因此Hash算法常用在不可还原的密码存储、数据完整性校验等领域。不可逆向解密

那问题来了,密码只能单向加密不能解密,那如何校验密码的正确性?我们来看Spring Security中的接口PasswordEncoder ,并对这个问题进行解答。

二、PasswordEncoder 接口


PasswordEncoder 是Spring Scurity框架内处理密码加密与校验的接口。

package org.springframework.security.crypto.password;

public interface PasswordEncoder {

//提供未加密的密码,返回被加密的密码的hash值

String encode(CharSequence rawPassword);

//判断用户输入的原始密码和上面encode()生成的加密的密码是否匹配

boolean matches(CharSequence rawPassword, String encodedPassword);

//判断当前被加密后的密码是否需要升级,也就是说,是否需要重新加密

default boolean upgradeEncoding(String encodedPassword) {

return false;

}

}

这个接口有三个方法

  • encode()方法接受的参数是原始密码字符串,返回值是经过加密之后的hash值,hash值是不能被逆向解密的。这个方法通常在为系统添加用户,或者用户注册的时候使用。

  • matches()方法是用来校验用户输入密码rawPassword,和加密后的hash值encodedPassword是否匹配。如果能够匹配返回true,表示用户输入的密码rawPassword是正确的,反之返回fasle。也就是说虽然这个hash值不能被逆向解密,但是可以判断是否和原始密码匹配。这个方法通常在用户登录的时候进行用户输入密码的正确性校验。

  • upgradeEncoding()设计的用意是,判断当前的密码是否需要升级。也就是是否需要重新加密?需要的话返回true,不需要的话返回fasle。默认实现是返回false。


例如,我们可以通过如下示例代码在进行用户注册的时候加密存储用户密码

user.setPassword(passwordEncoder.encode(user.getPassword()));

//将User保存到数据库表,该表包含password列


三、接口实现类


BCryptPasswordEncoder 是Spring Security推荐使用的PasswordEncoder接口实现类

@Test

void contextLoads() {

PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

String rawPwd = “123456”;

String encodePwd = passwordEncoder.encode(rawPwd);

System.out.println(“原始密码:”+rawPwd);

System.out.println(“加密后的密码::”+encodePwd);

System.out.println(rawPwd+“是否匹配”+encodePwd+“:” +passwordEncoder.matches(rawPwd,encodePwd));

System.out.println(“654321是否匹配”+encodePwd +“:”+passwordEncoder.matches(“654321”,encodePwd));

}

  • 结果

上面的测试用例执行的结果是下面这样的。(注意:对于同一个原始密码,每次加密之后的hash密码都是不一样的,这正是BCryptPasswordEncoder的强大之处,它不仅不能被破解,想通过常用密码对照表进行大海捞针你都无从下手)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EF5GN9Sd-1617534829688)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403203937.png)]

BCrypt产生随机盐(盐的作用就是每次做出来的菜味道都不一样)。这一点很重要,因为这意味着每次encode将产生不同的结果。

$2a 10 10 10zt6dUMTjNSyzINTGyiAgluna3mPm7qdgl26vj4tFpsFO6WlK5lXNm

BCrypt加密后的密码有三个部分,由 $分隔:

  1. "2a"表示 BCrypt 算法版本

  2. "10"表示算法的强度

  3. "zt6dUMTjNSyzINTGyiAglu"部分实际上是随机生成的盐。通常来说前 22 个字符是盐,剩余部分是纯文本的实际哈希值。

  4. “na3mPm7qdgl26vj4tFpsFO6WlK5lXNm” 文本的hash值

虽然每次生成的hash值都不一样,但是只要保证原始密码正确,再进行bcrypt加密,数据库储存的加密后的密码还是可以通过matches()方法进行匹配判断是否匹配

BCrypt*算法生成长度为 60 的字符串,因此我们需要确保密码将存储在可以容纳密码的数据库列中。


5、formLogin模式登录认证

===========================================================================

一、formLogin的应用场景


在本专栏之前的文章中,已经给大家介绍过Spring Security的HttpBasic模式,该模式比较简单,只是进行了通过携带Http的Header进行简单的登录验证,而且没有可以定制的登录页面,所以使用场景比较窄。

对于一个完整的应用系统,与登录验证相关的页面都是高度定制化的,非常美观而且提供多种登录方式。这就需要Spring Security支持我们自己定制登录页面,也就是本文给大家介绍的formLogin模式登录认证模式。

需要注意的是:有的朋友会被Form Login这个名字误解,Form Login不是只有使用html中的form 表单才能实现登录功能,使用js发起登录请求也是可以的

准备工作

  • 参考上面的《需求分析与基础环境准备》

  • 将《Http Basic模式登录认证》的配置内容从项目里面删掉

  • 仍然需要在项目里面通过maven引入如下坐标

org.springframework.boot

spring-boot-starter-security

  • 把下面的代码从BizpageController里面删掉。这涉及到一个非常重要的问题,就是Spring Security的登录认证并不需要我们自己去写登录认证的Controller方法,而是使用过滤器UsernamePasswordAuthenticationFilter(下一节会源码分析),这个过滤器是·默认集成的·,所以并不需要我们自己去实现登录认证逻辑。我们实现登录功能只需要做配置就可以了,所以把下面的代码从项目里面删掉。

// 登录

@PostMapping(“/login”)

public String index(String username,String password) {

return “index”;

}


二、说明


formLogin登录认证模式的三要素:

  • 登录认证逻辑-登录URL、如何接收登录参数、登陆成功后逻辑(静态)

  • 资源访问控制规则-决定什么用户、什么角色可以访问什么资源(动态-数据库)

  • 用户具有角色权限-配置某个用户拥有什么角色、拥有什么权限(动态-数据库)

一般来说,使用权限认证框架的的业务系统登录验证逻辑是固定的,而资源访问控制规则和用户信息是从数据库或其他存储介质灵活加载的。但本文所有的用户、资源、权限信息都是代码配置写死的,旨在为大家介绍formLogin认证模式,如何从数据库加载权限认证相关信息我还会结合RBAC权限模型再写文章的。

三、登录认证及资源访问权限的控制


首先,我们要继承WebSecurityConfigurerAdapter ,重写configure(HttpSecurity http) 方法,该方法用来配置登录验证逻辑。请注意看下文代码中的注释信息。

//登录认证及资源访问权限的控制

@Override

protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable()//关闭csrf防御

.formLogin()//开启formLogin认证

.loginPage(“/login.html”)//一旦用户的请求没有权限就跳转到这个页面

.loginProcessingUrl(“/login”)//登录表单form中action的地址,也就是处理认证请求的路径

.usernameParameter(“username”)//登录表单form中用户名输入框input的name名,不修改的话默认是username

.passwordParameter(“password”)//form中密码输入框input的name名,不修改的话默认是password

.defaultSuccessUrl(“/”)//如果用户输入了正确的账号密码,默认转跳的路径

.and()

.authorizeRequests()

.antMatchers(“/login.html”,“/login”).permitAll()//不需要通过验证就可以被访问的资源地址,permitAll()允许访问的方法

.antMatchers(“/”,“/biz1”,“biz2”)//资源路径配置

//hasAnyAuthority():有权限

.hasAnyAuthority(“ROLE_user”,“ROLE_admin”)//只要你是user角色和admin角色【其中之一】就可以访问:“/”,“/biz1”,“biz2”,指定都可以访问的角色

.antMatchers(“/syslog”,“/sysuser”)//资源路径配置

//hasAnyRole():有角色

.hasAnyRole(“admin”)//只要你是admin角色可以访问:“/syslog”,“/sysuser”

//.antMatchers(“/syslog”).hasAuthority(“sys:log”)

//.antMatchers(“/sysuser”).hasAuthority(“sys:user”) 访问(“/syslog”,“/sysuser”)请求需要携带(“sys:log”,“sys:user”)权限id ①①①①①①①

//hasAnyAuthority(“ROLE_user”,“ROLE_admin”) = hasAnyRole(“admin”) 的写法

//hasAnyAuthority只要在方法中加上ROLE_XXX 就等价于hasAnyRole(“XXXX”)的写法

.anyRequest().authenticated();

}

上面的代码分为两部分:

  • 第一部分是formLogin配置段,用于配置登录验证逻辑相关的信息。如:登录页面、登录成功页面、登录请求处理路径等。和login.html页面的元素配置要一一对应。

  • "/"在spring boot应用里面作为资源访问的时候比较特殊,它就是“/index.html”.所以defaultSuccessUrl登录成功之后就跳转到index.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ec6cjJsW-1617534829689)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403213223.png)]

  • 第二部分是authorizeRequests配置段,用于配置资源的访问控制规则。如:开发登录页面的permitAll开放访问,“/biz1”(业务一页面资源)需要有角色为user或admin的用户才可以访问。

  • hasAnyAuthority("ROLE_user","ROLE_admin")等价于hasAnyRole("user","admin"),角色是一种特殊的权限。

//hasAnyAuthority(“ROLE_user”,“ROLE_admin”) = hasAnyRole(“admin”) 的写法

//hasAnyAuthority只要在方法中加上ROLE_XXX 就等价于hasAnyRole(“XXXX”)的写法

  • "sys:log"或"sys:user"是我们自定义的权限ID,有这个ID的用户可以访问对应的资源

这时候我们通过浏览器访问,随便测试一个用户没有访问权限的资源,都会跳转到login.html页面。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLSkm3a3-1617534829691)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403213414.png)]


四、用户及角色信息配置


在上文中,我们配置了登录验证及资源访问的权限规则,我们还没有具体的用户,下面我们就来配置具体的用户。重写WebSecurityConfigurerAdapter的 configure(AuthenticationManagerBuilder auth)方法

  • 下面配置了两个用户

  • 用户名:密码:角色

  • 访问权限角色是上面设置的,这里设置的是用户和对应的角色是什么

  • user:123456:user(有权访问"/“,”/biz1",“biz2”)

  • admin:123456:admin(有权访问"/syslog",“/sysuser”,“/”,“/biz1”,“biz2”)

//用户及角色信息配置

@Override

public void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.inMemoryAuthentication()//存储在内存中的登录认证方式

.withUser(“user”)

.password(passwordEncoder().encode(“123456”))

.roles(“user”)

.and()

.withUser(“admin”)

.password(passwordEncoder().encode(“123456”))

//.authorities(“sys:log”,“sys:user”) //配置权限id(“sys:log”,“sys:user”)对应上面的①①①①①

.roles(“admin”)

.and()

.passwordEncoder(passwordEncoder());//配置使用BCrypt加密

}

//注入BCrypt加密

@Bean

public PasswordEncoder passwordEncoder(){

return new BCryptPasswordEncoder();

}

  • inMemoryAuthentication指的是在内存里面存储用户的身份认证和授权信息。

  • withUser("user")用户名是user

  • password(passwordEncoder().encode("123456"))密码是加密之后的123456

  • authorities("sys:log","sys:user")指的是admin用户拥有资源ID对应的资源访问的的权限:“/syslog"和”/sysuser"

  • roles()方法用于指定用户的角色,一个用户可以有多个角色


五、静态资源访问


在我们的实际开发中,登录页面login.html和控制层Controller登录验证’/login’都必须无条件的开放。除此之外,一些静态资源如css、js文件通常也都不需要验证权限,我们需要将它们的访问权限也开放出来。下面就是实现的方法:重写WebSecurityConfigurerAdapter类的configure(WebSecurity web) 方法

@Override

public void configure(WebSecurity web) {

//将项目中静态资源路径[开放]出来

web.ignoring().antMatchers( “/css/", "/fonts/”, “/img/", "/js/”);

}

那么这些静态资源的开放,和Controller服务资源的开放为什么要分开配置?有什么区别呢?

  • Controller服务资源要经过一系列的过滤器的验证,我们配置的是验证的放行规则

  • 这里配置的是静态资源的开放,不经过任何的过滤器链验证,直接访问资源


六、一个奇怪的问题


有朋友问:我们的login登录认证是通过配置实现的,我们没有写Controller,也只接收了username和password两个参数,那如果我们在登陆的时候有更多的参数需要接收该怎么办?

刚开始有朋友问我这个问题的时候,我真的感觉这个问题很奇怪,如果你不用spring security,该怎么获取参数?当然从Http Request里面去获取啊,怎么到了Spring security里面就不会了呢?后来问的同学越来越多,我发现这还真是一个普遍问题:不写Controller就不会传参了

统一答复:该怎么获取参数,哪里有HttpServletRequest,那里就能获取参数。比如:

  • 自定义一个Filter过滤器,过滤器里面肯定有HttpServletRequest吧。当然我们一般不在自定义过滤器里面去做实际业务处理,所以这种方法暂不考虑。

  • 另外就是我们后面章节为大家介绍的 《自定义登录验证结果处理》,在登录成功之后我们可以实现一定的业务逻辑(建议用这种) 。在这里面可以获取参数,想传多少参数就传多少。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssnUqScO-1617534829692)(http://qpgf4uqra.hn-bkt.clouddn.com/20210403223056.png)]

其实归根结底还是大家对于HTTP协议不清楚、Spring基础不扎实!HTTP 请求头、请求体、queryString等等很多传参渠道,Spring的过滤器、拦截器很多都可以HttpServletRequest拦截请求。


6、源码解析登录验证流程

======================================================================

一、登录认证基于过滤器链


Spring Security的登录验证流程核心就是过滤器链。

image-20210404121449408

  • 贯穿于整个过滤器链始终有一个上下文对象SecurityContext和一个Authentication对象(登录认证的主体)

  • 一旦某一个该主体通过其中某一个过滤器的认证,Authentication对象信息被填充,比如:isAuthenticated=true表示该主体通过验证。

  • 如果该主体通过了所有的过滤器,仍然没有被认证,在整个过滤器链的最后方有一个FilterSecurityInterceptor过滤器(虽然叫Interceptor,但它是名副其实的过滤器,不是拦截器)。判断Authentication对象的认证状态,如果没有通过认证则抛出异常,通过认证则访问后端API。

  • 之后进入响应阶段,FilterSecurityInterceptor抛出的异常被ExceptionTransactionFilter对异常进行相应的处理。比如:用户名密码登录异常,会被引导到登录页重新登陆。

  • 如果是登陆成功且没有任何异常,在请求响应中最后一个过滤器SecurityContextPersistenceFilter中将SecurityContext放入session。下次再进行请求的时候,直接从SecurityContextPersistenceFilter的session中取出认证信息。从而避免多次重复认证。


SpringSecurity提供了多种登录认证的方式,由多种Filter过滤器来实现,比如:

  • BasicAuthenticationFilter实现的是HttpBasic模式的登录认证

  • UsernamePasswordAuthenticationFilter实现用户名密码的登录认证

  • RememberMeAuthenticationFilter实现登录认证的“记住我”的功能

  • SocialAuthenticationFilter实现社交媒体方式登录认证的处理,如:QQ、微信

  • Oauth2AuthenticationProcessingFilter和Oauth2ClientAuthenticationProcessingFilter实现Oauth2的鉴权方式

根据我们不同的需求实现及配置,不同的Filter会被加载到应用中。


二、过滤器登录验证细节


image-20210404121708812

2.1.构建登录认证主体

如图所示,当用户登陆的时候首先被某一种认证方式的过滤器拦截(以用户名密码登录为例)。如:UsernamePasswordAuthenticationFilter会使用用户名和密码创建一个登录认证凭证:UsernamePasswordAuthenticationToken,进而获取一个Authentication对象,该对象代表身份验证的主体,贯穿于用户认证流程始终。

image-20210404130534577


2.2.多种认证方式的管理 ProviderManager

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

我的面试宝典:一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

image

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

image

还有源码相关的阅读学习

image

用户认证流程始终。

image-20210404130534577


2.2.多种认证方式的管理 ProviderManager

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-WVXn0Fud-1710689504114)]
[外链图片转存中…(img-btTpIhrG-1710689504115)]
[外链图片转存中…(img-KvRaH2QT-1710689504115)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-P0JXlucc-1710689504116)]

我的面试宝典:一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

[外链图片转存中…(img-CVMAaNDQ-1710689504116)]

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

[外链图片转存中…(img-f2KxCSAv-1710689504116)]

还有源码相关的阅读学习

[外链图片转存中…(img-znlo2Olk-1710689504117)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值