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();
    }
}

今日总结

  • 阅读源码

  • 使用自己的数据库

  • 密码加密

  • 修改密码

相关推荐
程序员小假16 分钟前
我们来说一下 MySQL 的慢查询日志
java·后端
独自破碎E38 分钟前
Java是怎么实现跨平台的?
java·开发语言
To Be Clean Coder1 小时前
【Spring源码】从源码倒看Spring用法(二)
java·后端·spring
xdpcxq10291 小时前
风控场景下超高并发频次计算服务
java·服务器·网络
想用offer打牌1 小时前
你真的懂Thread.currentThread().interrupt()吗?
java·后端·架构
橘色的狸花猫1 小时前
简历与岗位要求相似度分析系统
java·nlp
独自破碎E1 小时前
Leetcode1438绝对值不超过限制的最长连续子数组
java·开发语言·算法
用户91743965391 小时前
Elasticsearch Percolate Query使用优化案例-从2000到500ms
java·大数据·elasticsearch
yaoxin5211232 小时前
279. Java Stream API - Stream 拼接的两种方式:concat() vs flatMap()
java·开发语言
坚持学习前端日记2 小时前
2025年的个人和学习年度总结以及未来期望
java·学习·程序人生·职场和发展·创业创新