一、Spring Security框架的作用:
主要解决了认证与授权的相关问题。
二、概念
认证:识别客户端的身份,Spring Security只会根据SecurityContext中的认证信息(Authentication对象)来识别客户端的身份
授权:控制客户端是否允许访问某个资源
提示:登录是处理认证时非常重要且不可或缺的一个环节,在处理登录时,需要将通过登录验证后的结果(认证信息)存入到SecurityContext中,后续,Spring Security会自动从SecurityContext中找到认证信息,从而识别客户端的身份
三、Spring Security框架的基本特点
在Spring Boot 项目中,当添加了spring-boot-starter-security依赖后,你的项目会发生以下改变:
1.所有请求都是必须通过认证的,否则,会响应403,或重定向到默认的登录页面
2.提供了默认的登录页(/login)和登出页(/logout)
3.提供了默认的登录账号,用户名为user,密码为启动项目时的控制台提示的UUID值
4.默认开启了防止伪造的跨域攻击的防御机制,自定义的POST请求无法正常处理
四、关于Spring Security的配置类
在项目中,可以自定义类,继承自WebSecurityConfigurerAdaoter,则此类是Spring Security的配置类,在类中重写void configurer(HttpSecurity http)方法进行配置。
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
public void configurer(HttpSecurity http){
//配置请求的授权访问,注意:将使用第一匹配原则
http.authorizeRequests()
.mvcMatchers("/user/login","/user/reg") //匹配若干个路径,可以使用Any-Style通配模式
.permitAll() //允许直接访问,不需要检查认证信息
.anyRequest() //所有请求,也可以视为“除了以上配置过的以外的其他请求”
.authenticated(); //要求是已经通过认证的,则需要检查认证信息
//如果调用以下方法,将启用默认的登录页和登出页,当视为“认证未通过”时,将重定向到登录页
//如果不调用以下方法,将不启用默认的登录页和登出页,当视为“未通过认证”时,将响应403
//还可以在以下方法的基础上,进一步调用其他方法对登录页和登出页进行配置
http.formLogin();
//禁用【防止伪造的跨域攻击的防御机制】,则自定义的POST请求可以正常处理
http.csrf().disable();
}
}
关于Any-Style:
1.当使用 * 通配符时,例如:/user/*,可以匹配/user/login,但不匹配/user/9527/delete
2.当使用 ** 通配符时,例如:/user/**,可以匹配/user/login,也可以匹配/user/9527/delete
关于第一匹配原则 :
如果某个请求匹配以上配置的多种规则,将以第一次匹配到的为准,根据以上演示代码,/user/login
匹配到了mvcMatcher()
方法配置的路径,也匹配了anyRequest()
,由于mvcMatcher()
的代码靠前,则/user/login
请求适用于permitAll()
,而不会是authenticated()
,在实际应用中,可以简单的认为:需要将精准的配置写在靠前的位置,需要将模糊的配置写在靠后的位置
五、使用Spring Security验证登录
Spring Security 提供了UserDetailsService接口,接口中定义了UserDetails
loadUserByUsername(String username)方法,在验证登录时,Spring Security框架会自动使用登录时提交的用户名来调用这个方法,则框架将得到返回的userDetails类型的对象,并自动检查UserDetails对象中的用户状态,如果用户状态为不可用(被禁用,已过期等),则抛出异常,然后,还会自动验证登录时提交密码与UserDetails对象中的密码是否匹配,如果不匹配,则抛出异常,如果匹配,则验证完成,将返回Authyentication类型的结果。
假设提交了登录信息:root/123456
【以下是框架自动执行】
UserDetails userDetails=userDetailsService.loadUserByUsername("root");
检查userDetails对象中包含的用户状态,例如是否禁用、是否过期等
检查userDetails对象在包含的密码,与123456是否匹配
当需要自定义登录验证时,需要:
1. 在配置类中,使用@Bean方法配置密码编码器(PasswordEncoder)
1.1 Spring Security在验证密码是否匹配时,要求UserDetails类型的对象中的密码是某种密文格式
1.2 一般定义在Spring Security的配置类中即可
2. 在Spring Security配置类中,通过重写AuthenticationManager authenticationManagerBean()方法,并在方法上添加@Bean注解,则后续可以自动装配AuthenticationManager对象来执行登录验证
2.1不建议重写authenticationManager()方法,此方法在执行某些测试时会出现死循环,从而导致内存溢出
3. 自定义组件类,实现UserDetailsService接口,并重写loadUserByUsername()方法
3.1一旦Spring容器中存在UserDetailsService类型的对象,则Spring Security不在启用默认的登录账号,启动项目时控制台也不再显示临时的UUID密码
4.在需要执行登录验证的类中,先自动装配AuthenticationManager,然后再调用此对象的authenticate()方法即可执行登录验证
4.1提示:验证通过后,应该将authenticate()方法返回的结果存入到SecurityContext中,以保证后续能够通过认证
六、算法相关
1.关于UUID
UUID是全球唯一码,它保证了在同一时空中的值是唯一的
UUID的算法并不是固定的,各个平台生成的UUID的特征并不相同
UUID的主要特点:唯一,随机(不可预测)
UUID本质上是由128位算法(运算结果是128个二进制位)运算得到的结果,在显示时,通常会转换成十六进制数,长度为32,并且会在其中添加4个减号(典型格式为8-4-4-4-8),则总长度为36。
另外,128位算法的结果有2的128次方个
2.关于BCrypt算法
注意:所有用于处理密码加密并最终保存到数据库中所使用的的算法,都不是加密算法!所有的加密算法都是可以被逆向运算的,加密算法是用于保证传输过程的安全性的!用于处理密码加密并存储的加密都是单向算法,即使算法、加密参数、密文均被泄露也不可能通过运算还原出原始的密码(密码的原文)。
早期,典型的用于处理密码加密算法主要有:MDS、SHA-1等,这些算法可以被穷举手段进行破解的
BCrypt算法默认使用了随机的盐值,并且,此盐值被保存到密文中,作为密文的一部分,以便于后续验证密码。
BCrypt算法最大的特点就是“慢”!他被故意设计为一种慢速算法,可以有效地防止暴力破解(循环尝试)
BCrypt的算法的工具类是BCryptPasswordEncoder,这个累的构造方法可以传入参数,表示算法的强度值,默认为10,表示将进行2的10次方这么多次数的哈希运算,如果你认为现在执行的BCrypt太快而不安全,可以适当的调整这个值,值越大,执行哈希运算的次数就越多,整体运算速度就会越慢!