当前位置:   article > 正文

一文秒懂 springsecurity6.2实现自定义登录页_springsecurity6.2 自定义登陆和授权页面

springsecurity6.2 自定义登陆和授权页面

前言

springsecurity原理和基础这里暂时不讲,网上资料太多了,这个大家可以自行查找学习,基本上没什么太大区别,看几篇文章就了解了,这篇文章主要是针对自定义登录页做一个demo,通过这个小 demo,大家可以直接理解springsecurity 处理登录的流程。

在springsecurity 6.x之前的版本里,实现springsecurity web configuration 需要继承 WebSecurityConfigurerAdaper,但是在 6.X的新版本里,这个类已经不复存在了,而是使用 SpringSecurityFilterChain 而且有很多方法也都 depricated了,估计不久的将来,这些方法也会被 remove 掉,所以下面是基于springsecurity 6.2 版本实现的自定义登录页的功能,没有任何多余的代码,甚至从数据库查询user信息都是mock的,就是为了方便大家学习,网上看了很多资料,要么太繁琐,不知道核心在哪里,要么没办法复现,废话少说,直接上代码:

Springsecurity Filter Chain 配置:

  1. package com.boot.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  6. import org.springframework.security.crypto.password.NoOpPasswordEncoder;
  7. import org.springframework.security.crypto.password.PasswordEncoder;
  8. import org.springframework.security.web.SecurityFilterChain;
  9. @Configuration
  10. @EnableWebSecurity
  11. public class SecurityConfig {
  12. /**
  13. * PasswordEncoder:加密编码,这里使用 NoOpPasswordEncoder 明文密码,如果需要加密,用 BCryptPasswordEncoder
  14. */
  15. @Bean
  16. public PasswordEncoder passwordEncoder(){
  17. //明文加密
  18. return NoOpPasswordEncoder.getInstance();
  19. }
  20. @Bean
  21. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  22. http.authorizeHttpRequests(authorizeHttpRequests->
  23. authorizeHttpRequests
  24. .requestMatchers("/login").permitAll()
  25. // .requestMatchers(HttpMethod.POST, "/login").permitAll()
  26. .anyRequest().authenticated()
  27. );
  28. http.formLogin(formLogin->
  29. formLogin
  30. .loginPage("/mylogin.html")
  31. .loginProcessingUrl("/login")
  32. .permitAll()
  33. );
  34. // 注意 6.2 版本里这里要使用 csrf.disable() 而不是 withDefault() 方法,网上很多使用 withDefault()方法的,个人实践不成功
  35. http.csrf(csrf->csrf.disable());
  36. return http.build();
  37. }
  38. }

写一个普通的 controller,后面我们就用这个 /user/login 做测试

  1. @RestController
  2. public class LoginController {
  3. @GetMapping("/user/login")
  4. public String login(){
  5. return "login";
  6. }
  7. }

实现 UserDetailsService

  1. package com.boot.service.impl;
  2. import org.springframework.security.core.userdetails.UserDetails;
  3. import org.springframework.security.core.userdetails.UserDetailsService;
  4. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  5. import org.springframework.stereotype.Service;
  6. import org.springframework.security.core.userdetails.User;
  7. @Service
  8. public class UserDetailsServiceImpl implements UserDetailsService {
  9. @Override
  10. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  11. return User.withUsername("user")
  12. .password("123456")
  13. .build();
  14. }
  15. }

这里只是简单的创建了一个 user,实际情况下可以在这里查询 db 里的user,为了简单化流程,这里就略过查询 db 的逻辑了,大家可以自行根据 mybatis 处理这一块内容

自定义的登录页

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="https://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>登录页面</title>
  6. </head>
  7. <body>
  8. <h1 style="background-color: chocolate">欢迎登录</h1>
  9. <form action="/login" method="post">
  10. 用户名:<input type="text" name="username"><br/>
  11. 密码:<input type="text" name="password"><br/>
  12. <input type="submit" value="登录">
  13. </form>
  14. </body>
  15. </html>

注意这里的 form action 一定要和 SecurityConfig 里的 loginProcessUrl一致,具体原因后面讲,注意这个页面要放在 resources 下的 static 目录下,其他目录可能会跳转不成功

项目目录

简单说一下自定义登录页的原理

  1. /**
  2. * 配置问题的主要问题点:
  3. * 1. http.csrf(withDefaults()); 这个方式禁用csrf已经不起作用了,必须要 http.csrf(csrf->csrf.disable());
  4. * 2. 表单里的 action 一定要是 /login
  5. * 3. loginProcessingUrl("/login") 这个 /login 接口只是一个虚拟的接口,springsecurity 一旦看到 endpoint/login 就会触发
  6. * UsernamePasswordAuthenticationFilter 的校验逻辑,这个类会获取表单里的用户名和密码
  7. *
  8. * 在 Spring Security 中,所有的 HTTP 请求都会通过一系列的过滤器,这些过滤器组成了一个过滤器链。UsernamePasswordAuthenticationFilter
  9. * 就是其中的一个过滤器。每一个过滤器都对所有请求进行检查,看是否应该处理该请求。如果应该处理,该过滤器就会处理该请求;如果不应该处理,
  10. * 该过滤器就会将请求传递给过滤器链中的下一个过滤器。
  11. *
  12. * UsernamePasswordAuthenticationFilter 的工作方式就是检查每个传入的 HTTP 请求,看是否是一个 POST 请求,且请求的路径是否匹配登录路径
  13. * (默认是 /login,可以通过 .loginProcessingUrl("/yourLoginPath") 来修改)。如果满足这些条件,这个过滤器就会处理该请求,
  14. * 从请求参数中提取出用户名和密码,然后创建一个 UsernamePasswordAuthenticationToken,并将其传递给 AuthenticationManager。
  15. *
  16. * 这个过程是在 UsernamePasswordAuthenticationFilter 的 attemptAuthentication 方法中完成的。这个方法会检查请求的 HTTP 方法和路径,
  17. * 如果匹配,就处理该请求;如果不匹配,就返回 null,将处理权交给过滤器链中的下一个过滤器。
  18. *
  19. */

测试

访问 http://localhost:8886/user/login 会跳转到 mylogin.html 上:

输入用户名和密码,可以发现请求又被重定向回 /user/login 接口,而且访问成功:

Tips:

建议大家在测试的时候用 chrom 浏览器的隐身模式,快捷键: ctrl+shift+n

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/84294
推荐阅读
相关标签
  

闽ICP备14008679号