SpringSecurity

SpringSecurity

总课程计划

  • 第一课:主要学习理论知识,框架搭建

  • 第二课:认证的实际运用

  • 第三课:授权

  • 第四课:第四阶段,微服务下的运用

今日课程计划

  • 搭建一个SpringSecurity项目

  • 介绍用户名密码登录过滤器

  • 登录流程

  • 阅读源码

  • 使用自己的数据库登录

  • 密码加密

  • 修改密码

  • 注销登录

今日学习目标

  • 认识用户名密码过滤器

  • 能够自己配置使用自定义数据库

认证---页面

一、介绍

  • 是安全框架

  • 认证

    • 能不能登录
  • 授权

    • 登录成功之后,能访问什么
  • 防止网络攻击

认证和授权是独立的

二、安全框架的几种方案

1、自己实现

自定义注解 搭配web的拦截器,来控制url地址能否访问。

自定义注解 搭配AOP,来控制某个方法能否访问。

优点:实现快速方便,使用简单,规则都是自己定义的,在公司内部使用方便修改。

缺点:重新学习本公司特有的权限体系,无法防御网络攻击(Sentinel去弥补)

2、Shiro

优点:整合方便,使用简单

缺点:在微服务体系下,不够安全

3、SpringSecurity

优点:能够适应复杂的业务场景,比较适合在微服务体系内使用

缺点:代码复杂,学习难度高,配置多,不容易整合

三、搭建项目

1、新建项目

2、添加依赖

复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

3、启动测试

Security框架在引入之后,自动配置成功,并且自动生效

只要加入了依赖,就会帮助你,拦截所有的请求

被拦截的请求,都会统一的跳转到登录页面

使用自动生成的用户名密码登录

默认的用户名:user

默认的密码:查看控制台

现在所有的请求,都会被拦截,重定向到/login页面。

登录成功之后,又会重定向到之前(最后一次)访问的页面。

  • ApiFox访问

四、流程

在SpringSecurity中存在一个过滤器链

这个过过滤器链在一个list中存储,他们之间是有顺序的。

默认情况下,启动的时候,Security会生成默认的用户名和密码,把密码打印到控制台上。

如果后续用于自定义了用户名和密码(使用了自己的用户名和密码)这个流程会消失。

Security中,每个功能,都是使用过滤器来实现的。

最上层第一个被访问的过滤器,是ExceptionTrancationFilter

登录的时候,要经过的过滤器:

  • UsernamePasswordAuthenicationFilter

    • 接收页面传入的参数

    • 拼装成实体类

    • 传递给下一层Provider

    • 校验密码是否正确

    • 重新拼装实体类,返回给Filter

    • 返回的用户信息实体类,存储到上下文对象

8、整体流程

五、自定义登录页面

1、创建HTML页面

在resources文件夹里的static中创建页面

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <form action="/javasmlogin" method="post">
        <p>
            <input type="text" placeholder="用户名" name="uname">
        </p>
        <p>
            <input type="password" placeholder="用户名" name="pwd">
        </p>
        <p>
            <input type="submit" value="登录">
        </p>
    </form>
</body>
</html>

2、添加配置类

复制代码
​
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
​
@Configuration
@EnableWebSecurity
public class SecurityConfig {
​
    //配置SecuritFilterChain 自定义登录页面,认证规则
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        //http对象,支持链式调用
        //关闭csrf 跨域请求伪造的控制
        http.csrf(csrf -> csrf.disable());
        http.authorizeHttpRequests(
                auth ->
                        auth.requestMatchers("/loginpage.html", "/login/**")
                                .permitAll()
                                .anyRequest().authenticated()  //其他页面,要登录之后才能访问
        );//放过登录接口,以及静态页面
        //  ↓配置表单提交
        http.formLogin(form -> {
            form.loginPage("/loginpage.html")        //自定义登录页面的路径
                    .loginProcessingUrl("/javasmlogin")     //表单提交的路径
                    .usernameParameter("uname")              //自定义用户名的参数名(默认是username)
                    .passwordParameter("pwd")
                    .defaultSuccessUrl("/index.html", true)  //登录成功之后,跳转的页面,true表示强制跳转
                    .failureUrl("/loginpage.html?error=true")   //登录失败之后,返回的页面,可以自定义
                    .permitAll();     //以上提到的路径,都放行
        });
        //注销登录
        http.logout(logout->logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/loginpage.html")//注销成功之后,跳转的路径
                .permitAll()
        );
        return http.build();
​
    }
}
​

3、配置静态用户名和密码

过渡测试,帮助大家理解UserDetails的作用

这个代码在后续接入数据库之后,会删除

复制代码
    @Bean
    public UserDetailsService userDetailsService(){
        //密码已经改成了静态的 amdin 和 123
        //{noop} 表示密码不加密,在添加了加密算法之后,这个标识会失效
        UserDetails user = User.withUsername("admin").password("{noop}123").roles("ADMIN").build();
        return new InMemoryUserDetailsManager(user);
    }

六、使用自己的数据库的用户名和密码

1、配置整合MyBatiPlus

参考之前的项目

2、生成代码

在Security框架逻辑中,添加自己的逻辑,查询自己的数据库。

密码在默认情况下是不加密的,需要加上{noop}前缀

添加一条测试数据

3、UserDetails

复制代码
@NoArgsConstructor
@Getter
public class LoginUserDetails implements UserDetails {
​
    private AdminUser adminUser;
​
    public LoginUserDetails(AdminUser adminUser) {
        this.adminUser = adminUser;
    }
​
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        //存储授权列表
        return List.of();
    }
​
    @Override
    public String getPassword() {
        //密码
        return adminUser.getPassword();
    }
​
    @Override
    public String getUsername() {
        //用户名
        return adminUser.getUsername();
    }
    //【一定记得把下方四个方法的返回值改成true】
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
​
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
​
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
​
    @Override
    public boolean isEnabled() {
        return true;
    }
}

4、UserDetailsService

复制代码
@Service
public class UsernameLoginUserDetailsServiceImpl implements UserDetailsService {
​
    @Resource
    AdminUserService adminUserService;
​
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        AdminUser adminUser = adminUserService.getByUsername(username);
        if (adminUser != null){
            return new LoginUserDetails(adminUser);
        }
        return null;
    }
}

5、注释掉静态用户名和密码

6、测试

七、密码加密

在配置来看密码加密之后,{noop}就失效了。

所有的密码,都必须是加密之后的密码

1、修改配置类

复制代码
@Bean
public PasswordEncoder passwordEncoder(){
    //指定加密算法
    return new BCryptPasswordEncoder();
}

2、修改密码

现有的密码已经无法使用,需要一个接口,来修改密码

  • Controller
复制代码
@RestController
@RequestMapping("/login")
public class LoginController {
​
    @Resource
    LoginService loginService;
​
    @PutMapping("/update/password")
    public R updatePassword(Integer uid,String password){
        loginService.updatePassword(uid,password);
        return R.ok();
    }
}
  • Service
复制代码
@Service
public class LoginServiceImpl implements LoginService {
    
    @Resource
    PasswordEncoder passwordEncoder;
    
    @Override
    public void updatePassword(Integer uid, String password) {
        //把不加密的密码,改成加密的密码
        String newPassword = passwordEncoder.encode(password);
        AdminUser adminUser = new AdminUser();
        adminUser.setUid(uid);
        adminUser.setPassword(newPassword);
        adminUser.updateById();
    }
}

今日总结

  • 阅读源码

  • 使用自己的数据库

  • 密码加密

  • 修改密码

相关推荐
明月别枝惊鹊丶37 分钟前
【C++】GESP 三级手册
java·开发语言·c++
毕设源码-钟学长39 分钟前
【开题答辩全过程】以 公交线路查询系统为例,包含答辩的问题和答案
java
梵得儿SHI39 分钟前
SpringCloud - 核心组件精讲:Nacos 深度解析(服务注册 + 配置中心一站式实现)
java·spring boot·spring cloud·nacos·微服务架构的核心组件·服务注册发现与配置管理·nacos的核心原理与实战应用
不如打代码KK40 分钟前
Java SPI与Spring Boot SPI的区别
java·开发语言·spring boot
非凡的小笨鱼43 分钟前
利用arthas查看java服务里指定对象的大小
java·spring·arthas
代码or搬砖1 小时前
自定义注解全面详解
java·开发语言
爱上妖精的尾巴1 小时前
5-39 WPS JS宏 综合实例应用-4(多条件筛选记录并排序)
java·后端·restful·wps·js宏·jsa
柯南二号1 小时前
【后端】【Java】可直接落地的 Nginx + Java(Spring Boot)+ Redis 的短链系统实现
java·spring boot·nginx
廋到被风吹走1 小时前
【Spring】对多线程的支持
java·后端·spring
pyniu1 小时前
redis day1
java·前端·spring