• springsecurity学习笔记-未完


    前言

    记录一下学习springsecurity的过程

    开发环境:IDEA,springsecurity6


    一、概念

    1.什么是springsecurity

    spring提供的安全管理框架,核心功能是认证,授权

    认证:验证当前用户是不是本系统注册的用户,识别具体是哪个用户

    授权:通过认证的用户,需要判断是否具有权限进行某个操作

    2.对比shiro

    springsecurity功能更强大,shiro更容易上手应用

    3.执行过程

    初学阶段,从我的角度来说,最重要的是先用起来,底层逻辑在一开始我并不重视,但要知道的是整个执行过程是一组过滤器链,核心过滤器有三个

    UsernamePasswordAuthenticationFilter:用户名密码认证过滤器,处理登录请求

    ExceptionTranslationFilter:异常转换过滤器

    FilterSecurityInterceptor:权限过滤器

    二、开始项目

    1.建立一个空项目,建立module,引入相关依赖

    new Project->Empty Project

    File->new module->Spring Initializr->Maven->选择需要加入的功能->生成项目,等待依赖导入

    必须选择的包括springsecurity,springweb,注意右上角选择自己想要的springboot版本,springboot版本与jdk版本要匹配,否则可能会导致其他依赖的版本混乱

    附上依赖pom

    1. "1.0" encoding="UTF-8"?>
    2. "http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. 4.0.0
    5. org.springframework.boot
    6. spring-boot-starter-parent
    7. 3.1.2
    8. com.example
    9. demo
    10. 0.0.1-SNAPSHOT
    11. crm
    12. Demo project for Spring Boot
    13. 17
    14. org.springframework.boot
    15. spring-boot-starter-security
    16. org.springframework.boot
    17. spring-boot-starter-thymeleaf
    18. org.springframework.boot
    19. spring-boot-starter-web
    20. org.thymeleaf.extras
    21. thymeleaf-extras-springsecurity6
    22. org.springframework.boot
    23. spring-boot-devtools
    24. runtime
    25. true
    26. org.projectlombok
    27. lombok
    28. true
    29. org.springframework.boot
    30. spring-boot-starter-test
    31. test
    32. org.springframework.security
    33. spring-security-test
    34. test
    35. org.springframework.boot
    36. spring-boot-maven-plugin
    37. org.projectlombok
    38. lombok

    2.启动项目,访问项目

    控制台输出如下,意思是自动生成了密码,如果你要在生产环境使用,应该修改配置

    1. Using generated security password: 7bc86ae1-30a1-435c-bc59-6d894a7ae0b6
    2. This generated password is for development use only. Your security configuration must be updated before running your application in production.

    访问项目localhost:8080,以往我们访问本地项目,直接会进入首页,但这次弹出了一个登录页面

    这是springsecurity自带的过滤器,验证当前用户没有登陆,自动跳转到登录页面

    这个页面是通过网络下载的bootstrap页面,如果下载的有问题,那么页面展示效果可能会不太好,可以忽略

    输入账号密码登录,默认账号为user,密码为刚刚控制台输出的

    登陆后跳转到error页面,这并不是登录失败了,只是没有识别到登陆成功后应该跳转到哪

    我们可以自己写一个接口访问,比如http://localhost:8080/index,页面输出hello world!

    1. @RestController
    2. public class IndexController {
    3. @GetMapping("/index")
    4. public String index() {
    5. return "hello world!";
    6. }
    7. }

    3.自定义密码

    如果我们不想使用默认生成的密码,可以自己配置密码application.yml

    1. spring:
    2. security:
    3. user:
    4. name: admin
    5. password: 1234

    那么刚才我们没有配置密码的时候,默认密码是怎么生成的呢,security的User类给name和password提供了默认值

    1. private String name = "user";
    2. private String password = UUID.randomUUID().toString();

    4.自定义登陆页面

    显然我们不可能使用security提供的登陆页面

    如何让springsecurity能够跳转到我们自定义的登陆页面并验证呢

    1.编写页面

    注意:
    1.这里@{/login},@{/logout}指的是springsecurity提供的认证和退出接口,不是我们自己手写的访问接口

    2.这里使用了thymeleaf模板引擎,页面存放在templates目录下,如果不用引擎,应当作为静态页面存放在static下,或者通过spring.web.resources.static-locations配置

    3.@{/login}的入参必须是username,password,切记不能自由发挥

    1. login.html
    2. html>
    3. <html lang="en" xmlns:th="https://www.thymeleaf.org">
    4. <head>
    5. <meta charset="UTF-8">
    6. <title>登录title>
    7. head>
    8. <body>
    9. <h1>你好h1>
    10. <form th:action="@{/login}" method="post">
    11. 用户名:<input type="text" name="username">
    12. 密码:<input type="password" name="password">
    13. <input type="submit" value="登录">
    14. form>
    15. body>
    16. html>
    17. index.html
    18. html>
    19. <html lang="en" xmlns:th="https://www.thymeleaf.org">
    20. <head>
    21. <meta charset="UTF-8">
    22. <title>首页title>
    23. head>
    24. <body>
    25. hello world!
    26. <form th:action="@{/logout}" method="post">
    27. <input type="submit" value="退出">
    28. form>
    29. body>
    30. html>

    2.编写跳转页面的接口

    注意:
    1.login.html也可写作login

    2.使用@Controller,而不是@RestController,当然也不可以使用@ResponseBody,因为这样会使返回值成为一个字符串,而不是页面

    1. @Controller
    2. public class LoginController {
    3. /**
    4. * 登录页
    5. *
    6. * @return
    7. */
    8. @RequestMapping("/login")
    9. public String login() {
    10. return "login.html";
    11. }
    12. /**
    13. * 首页
    14. *
    15. * @return
    16. */
    17. @RequestMapping("/index")
    18. public String index() {
    19. return "index.html";
    20. }
    21. }


    3.配置springsecurity
     

    1. import org.springframework.context.annotation.Bean;
    2. import org.springframework.context.annotation.Configuration;
    3. import org.springframework.security.config.Customizer;
    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.web.SecurityFilterChain;
    7. @Configuration
    8. @EnableWebSecurity  //开启springsecurity,自动引入过滤器链SecurityFilterChain
    9. public class SecurityConfig {
    10.     @Bean
    11.     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    12.         /*
    13.             security6
    14.             authorizeHttpRequests():针对http请求的授权配置
    15.                 requestMatchers:匹配http请求url,此处指定为/login
    16.                 permitAll:给与所有权限,即允许匿名访问(不登陆直接访问)
    17.                 anyRequest:其它的所有的请求
    18.                 authenticated:需要认证
    19.          */
    20.         http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
    21.                 authorizationManagerRequestMatcherRegistry
    22.                         .requestMatchers("/login")
    23.                         .permitAll()
    24.                         .anyRequest()
    25.                         .authenticated()
    26.         );
    27.         /*
    28.             loginPage:登陆页面
    29.             loginProcessingUrl:登录接口
    30.             defaultSuccessUrl:登陆成功跳转
    31.          */
    32.         http.formLogin(httpSecurityFormLoginConfigurer ->
    33.                 httpSecurityFormLoginConfigurer
    34.                         .loginPage("/login").permitAll()
    35.                         .loginProcessingUrl("/login")
    36.                         .defaultSuccessUrl("/index")
    37.         );
    38.         //关闭跨域漏洞防御
    39.         http.csrf(Customizer.withDefaults());
    40.         //退出
    41.         http.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer.invalidateHttpSession(true));
    42.         //security5,已经被标记为过时,不建议
    43. //        http.authorizeHttpRequests()
    44. //                .requestMatchers("/public/**")
    45. //                .permitAll()
    46. //                .anyRequest()
    47. //                .hasRole("USER")
    48. //                .and()
    49. //                .formLogin()
    50. //                .permitAll();
    51.         return http.build();
    52.     }
    53. }

    5.前后端分离登录配置

    此处不讨论前端页面,只关注security配置

    与前后端不分的区别:去掉了登录页面和默认跳转页面,相当于入口由前端项目控制,前端页面拿到登录成功的返回值后,通过路由控制跳转首页

    1. import org.springframework.context.annotation.Bean;
    2. import org.springframework.context.annotation.Configuration;
    3. import org.springframework.security.config.Customizer;
    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.web.SecurityFilterChain;
    7. @Configuration
    8. @EnableWebSecurity //开启springsecurity,自动引入过滤器链SecurityFilterChain
    9. public class SecurityConfig {
    10. @Bean
    11. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    12. /*
    13. security6
    14. authorizeHttpRequests():针对http请求的授权配置
    15. requestMatchers:匹配http请求url,此处指定为/login
    16. permitAll:给与所有权限,即允许匿名访问(不登陆直接访问)
    17. anyRequest:其它的所有的请求
    18. authenticated:需要认证
    19. */
    20. http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
    21. authorizationManagerRequestMatcherRegistry
    22. .requestMatchers("/login")
    23. .permitAll()
    24. .anyRequest()
    25. .authenticated()
    26. );
    27. /*
    28. loginProcessingUrl:指定登录接口,即前端点击登陆时需要调用的接口名,默认值为/login
    29. successHandler:成功处理
    30. failureHandler:失败处理
    31. */
    32. http.formLogin(httpSecurityFormLoginConfigurer ->
    33. httpSecurityFormLoginConfigurer
    34. .loginProcessingUrl("/login")
    35. .successHandler(new LoginSuccessHandler())
    36. .failureHandler(new LoginFailureHandler())
    37. );
    38. //关闭跨域漏洞防御,跨域拦截
    39. http.csrf(Customizer.withDefaults()).cors(Customizer.withDefaults());
    40. //退出
    41. http.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer.invalidateHttpSession(true));
    42. //security5,已经被标记为过时,不建议
    43. // http.authorizeHttpRequests()
    44. // .requestMatchers("/public/**")
    45. // .permitAll()
    46. // .anyRequest()
    47. // .hasRole("USER")
    48. // .and()
    49. // .formLogin()
    50. // .permitAll();
    51. return http.build();
    52. }
    53. }
    1. import jakarta.servlet.ServletException;
    2. import jakarta.servlet.http.HttpServletRequest;
    3. import jakarta.servlet.http.HttpServletResponse;
    4. import org.springframework.security.core.AuthenticationException;
    5. import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    6. import java.io.IOException;
    7. public class LoginFailureHandler implements AuthenticationFailureHandler {
    8. @Override
    9. public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    10. response.setContentType("text/html;charset=UFT-8");
    11. response.getWriter().write("loginNo");
    12. exception.printStackTrace();
    13. }
    14. }
    1. import jakarta.servlet.ServletException;
    2. import jakarta.servlet.http.HttpServletRequest;
    3. import jakarta.servlet.http.HttpServletResponse;
    4. import org.springframework.security.core.Authentication;
    5. import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    6. import java.io.IOException;
    7. public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    8. @Override
    9. public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    10. response.setContentType("text/html;charset=UFT-8");
    11. response.getWriter().write("loginYes");
    12. authentication.getPrincipal();
    13. authentication.getAuthorities();
    14. authentication.getCredentials();
    15. }
    16. }

    三、权限

    在实际应用中,通常使用角色控制菜单的访问,通过权限控制接口的访问(即功能的访问)

    看一下增加了权限的SecurityConfig文件

    authorizeHttpRequests:增加角色,权限配置

    InMemoryUserDetailsManager:在内存中配置几个用户,后续可以改为读取数据库

    PasswordEncoder:密码编码器,给密码加密

    1. package com.example.crm.config.login;
    2. import org.springframework.boot.autoconfigure.security.SecurityProperties;
    3. import org.springframework.context.annotation.Bean;
    4. import org.springframework.context.annotation.Configuration;
    5. import org.springframework.security.config.Customizer;
    6. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    7. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    8. import org.springframework.security.core.userdetails.User;
    9. import org.springframework.security.core.userdetails.UserDetails;
    10. import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    11. import org.springframework.security.crypto.password.PasswordEncoder;
    12. import org.springframework.security.provisioning.InMemoryUserDetailsManager;
    13. import org.springframework.security.web.SecurityFilterChain;
    14. @Configuration
    15. @EnableWebSecurity //开启springsecurity,自动引入过滤器链SecurityFilterChain
    16. public class SecurityConfig {
    17. @Bean
    18. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    19. /*
    20. security6
    21. authorizeHttpRequests():针对http请求的授权配置
    22. requestMatchers:匹配http请求url,此处指定为/login
    23. permitAll:允许匿名访问(不登陆直接访问)
    24. hasRole,hasAnyRole:指定访问角色
    25. hasAuthority,hasAnyAuthority:指定权限
    26. anyRequest:其它的所有的请求
    27. authenticated:需要认证
    28. */
    29. http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
    30. authorizationManagerRequestMatcherRegistry
    31. .requestMatchers("/login").permitAll()
    32. // .requestMatchers("admin/*").hasRole("admin")
    33. // .requestMatchers("user/*").hasAnyRole("admin", "user")
    34. .requestMatchers("admin/*").hasAuthority("admin:get")
    35. .requestMatchers("user/*").hasAnyAuthority("admin:get", "user:get")
    36. .anyRequest().authenticated()
    37. );
    38. /*
    39. formLogin:针对登录的配置
    40. loginProcessingUrl:指定登录接口,即前端点击登陆时需要调用的接口名,默认值为/login
    41. successHandler:成功处理
    42. failureHandler:失败处理
    43. */
    44. http.formLogin(httpSecurityFormLoginConfigurer ->
    45. httpSecurityFormLoginConfigurer
    46. .loginProcessingUrl("/login")
    47. .successHandler(new LoginSuccessHandler())
    48. .failureHandler(new LoginFailureHandler())
    49. );
    50. /*
    51. * 异常处理
    52. */
    53. http.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> httpSecurityExceptionHandlingConfigurer.accessDeniedPage("/exception"));
    54. //关闭跨域漏洞防御,跨域拦截
    55. http.csrf(Customizer.withDefaults()).cors(Customizer.withDefaults());
    56. //退出
    57. http.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer.invalidateHttpSession(true));
    58. return http.build();
    59. }
    60. //用户
    61. @Bean
    62. public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
    63. UserDetails admin = User
    64. .withUsername("admin").password("1234")
    65. // .roles("admin", "user")
    66. .authorities("admin:get", "user:get")
    67. .build();
    68. UserDetails user = User.withUsername("user").password("1234").roles("user").build();
    69. return new InMemoryUserDetailsManager(admin, user);
    70. }
    71. //密码编码器
    72. @Bean
    73. public PasswordEncoder passwordEncoder() {
    74. return NoOpPasswordEncoder.getInstance();
    75. }
    76. }

  • 相关阅读:
    【机器学习】04. 神经网络模型 MLPClassifier分类算法与MLPRegressor回归算法(代码注释,思路推导)
    酷开科技夯实流量基础,构建智慧生活新风尚!
    数据库基本操作:如何查询数据库和创建表,以及查看表,复制表,删除表,添加主键,修改主键,删除主键
    [附源码]计算机毕业设计基于Springboot学生社团信息管理系统
    Vuex的简介以及入门案例
    【光学】基于matlab GUI双孔干涉【含Matlab源码 2119期】
    Flink开发语言使用Java还是Scala合适?
    触发迅雷下载
    Spring Cloud Netflix
    leetcode《图解数据结构》刷题日志【第五周】(2022/11/21-2022/11/28)
  • 原文地址:https://blog.csdn.net/qq_41358151/article/details/134057924