第四阶段13-关于Spring Security框架续(认证和授权)

本文深入探讨了Spring Security框架在防止伪造跨域攻击、BCrypt算法、PasswordEncoder接口的应用,以及前后端分离登录的实现。此外,还详细介绍了认证标准、识别当事人、授权访问的策略,并提供了具体的配置和代码示例,帮助理解Spring Security的安全机制。
摘要由CSDN通过智能技术生成

关于防止伪造的跨域攻击

**伪造的跨域攻击:**此类攻击主要源自“服务器端对客户端的浏览器的信任”(本质上是浏览器对同一个服务器端会携带同一个Session ID),例如,用户在浏览器的第1个选项卡中登录了,在第2个、第3个等等其它选项卡访问同样的服务器,也会被视为“已登录”的状态。所以,假设某用户在浏览器的第1个选项卡中登录了网上银行,第2个选项卡打开其它某个恶意的网站(并不是网上银行),此网站中隐藏了一个网上银行发起请求的链接,并会自动提交(比较典型的做法就是把链接做为<img>标签的src值,并隐藏此<img>标签使之不显示),则会导致在第2个选项卡中打开恶意网站时就向网上银行发出了请求,网上银行接收到此请求时,也会视为“已登录”的状态!虽然通过这种手段基本上无法实现财产的窃取,但仍可以做一些其它的数据窃取。

**典型的防御手段:**在“非前后端分离”的开发模式下,服务器端在生成表单时,会在表单中隐藏一个具有“唯一性”或较强的“随机性”的值,正常提交表单时,此值会随着表单数据一并提交到服务器端,所以,服务器端会根据是否正确的提交了这个值,来判断是否是通过正常方式提交的请求。以Spring Security的默认登录表单为例:
请添加图片描述

**注意:**在“前后端分离”的项目中,由于服务器端不负责生成各表单页面,所以,也无法在表单中添加UUID值,则客户端提交的请求中也无法提交正确的UUID值,所以,这种防御机制并不适用!

在Spring Security的配置类中,调用HttpSecurity对象的csrf().disable()方法可以禁用此防御机制,则POST请求不再被要求提交UUID值,是可以正常使用的!例如:

@Override
protected void configure(HttpSecurity http) throws Exception {
   
    // 禁用“防止伪造的跨域攻击”这种防御机制
    http.csrf().disable();

    // 暂不关心其它配置的代码
}

关于BCrypt算法

BCrypt算法是目前用于处理密码加密存储时最安全的算法之一!

在Spring Security框架中,自带了BCryptPasswordEncoder类,用于执行加密与对比。

public class BCryptTests {
   

    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Test
    void encode() {
   
        String rawPassword = "123456";
        System.out.println("原文:" + rawPassword);

        for (int i = 0; i < 10; i++) {
   
            String encodedPassword = passwordEncoder.encode(rawPassword);
            System.out.println("密文:" + encodedPassword);
        }
        // 原文:123456
        // 密文:$2a$10$i9E1pAtpQXIV4uUOjNr7ve/SWM9BDQl4hxq7Qz.kYDeLHTJwKhr7K
        // 密文:$2a$10$GCBOO7x7r8TjACK.ujA3oeft2uoKBTUm2L8UbWTRlnaugIupQB2Aq
        // 密文:$2a$10$osWYVZT3aBnG9h9ACiS8Mup3Hu4gjx1Lf46OIrjmseICX1cEPXZO6
        // 密文:$2a$10$r9l2Yced59FDWSFgh.mvmeAEyVQ9utfnEJJKuawO/17ndBT/xCF1q
        // 密文:$2a$10$A2DhHyIOTmWFbekRwM.wuOMSYQ1xVail7q3b1jkM4bdOjNJmfHuFK
        // 密文:$2a$10$YdvML3WsSlMghscfry/zkO67Yp8HZuVakMAXXDtuN.xmZUjVGcp5i
        // 密文:$2a$10$F.SxK1hRERQN6rwDIKw2BeD/wNXndICBs7pB9KJ7.rb9hqGVmpeeS
        // 密文:$2a$10$vtLCxMWTylqcqLwdcQpzIO00oT.lmULR9aQoelfP4BP6/0FBa2ckG
        // 密文:$2a$10$NX.BX7byguflK6G4/lQhVuJZZbekko.6h69Tilvdu2uMGHJuQCxi.
        // 密文:$2a$10$PNwmIXSRmy5yISsdbW1/Jusq4xwRx1KbkNGu.uJC2fYiHRQjOkWvS
    }

    @Test
    void matches() {
   
        String rawPassword = "123456";
        String encodedPassword = "$2a$10$osWYVZT3aBnG9h9ACiS8Mup3Hu4gjx1Lf46OIrjmseICX1cEPXZO6";
        boolean result = passwordEncoder.matches(rawPassword, encodedPassword);
        System.out.println("原文:" + rawPassword);
        System.out.println("密文:" + encodedPassword);
        System.out.println("匹配结果:" + result);
    }

}

BCrypt算法是一个运算效率极低的算法,可以非常有效的避免穷举式的暴力破解,这也是BCrypt算法的核心优势之一!

关于PasswordEncoder

PasswordEncoder是一个接口,BCryptPasswordEncoderNoOpPasswordEncoder都是其典型的实现类。

Spring Security框架在处理认证时(判断尝试登录的账号的密码是否正确时),会自动使用PasswordEncoder中的matches()方法将原文和密文进行对比,所以:

  • 你需要配置某个PasswordEncoder对象到Spring容器中
  • UserDetailsService接口中的loadUserByUsername()方法,返回的UserDetails接口类型的对象中的password应该与你配置的PasswordEncoder使用的算法是对应的

使用前后端分离的登录

首先,要保证默认的登录表单不被启用,即:在Spring Security的配置类中,不再使用http.formLogin()方法!

然后:

  • 需要使用控制器(Controller)接收来自客户端提交的用户名和密码
    • 建议自定义POJO将客户端提交的数据封装起来
  • 在Service层中处理登录的认证
    • 具体的处理,仍交由Spring Security来实现,需要调用AuthenticationManager(认证管理器)对象的authenticate()方法,则Spring Security会自动调用UserDetailsService接口对象的loadUserByUsername()方法获取用户信息详情并自动验证此用户是否允许登录

所以,在项目的根包下创建pojo.dto.AdminLoginDTO类,用于封装客户端提交的用户名和密码:

@Data
public class AdminLoginDTO implements Serializable {
   
    private String username;
    private String password;
}

然后,在Spring Security的配置类(自定义的SecurityConfiguration类)中重写authenticationManagerBean()方法,并在此方法上添加@Bean注解,则Spring会自动调用此方法,得到AuthenticationManager类型的对象,并保存在Spring容器中,后续,需要AuthenticationManager时可以自动装配!

@Bean // 重要
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
   
    return super.authenticationManagerBean();
}

**注意:**以上重写的是authenticationManagerBean()方法,而不是authenticationManager()方法!如果重写错误,在后续某此测试中会出现死循环,导致内存溢出!

IAdminService接口中添加抽象方法:

void login(AdminLoginDTO adminLoginDTO);

AdminServiceImpl中重写以上方法:

@Autowired
private AuthenticationManager authenticationManager;

@Override
public void login(AdminLoginDTO adminLoginDTO) {
   
    log.debug("开始处理【管理员登录】的业务,参数:{}", adminLoginDTO);
    Authentication authentication 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值