spring security入门

  1. 什么是spring security?

    spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。

  2. 认证和授权

    • 添加依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
    • 重要的三个类

      • WebSecurityConfigurerAdapter:自定义Security策略
      • AuthenticationManagerBuilder:自定义认证策略
      • @EnableWebSecurity:开启WebSecurity模式
    • 编写基础配置类

    package com.test.config;
    
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @EnableWebSecurity // 开启WebSecurity模式,要继承WebSecurityConfigurerAdapter这个类
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
       @Override
       protected void configure(HttpSecurity http) throws Exception {
           // 定制请求的授权规则
           // 首页所有人可以访问
           http.authorizeRequests().antMatchers("/").permitAll()
          .antMatchers("/level1/**").hasRole("vip1")
          .antMatchers("/level2/**").hasRole("vip2")
          .antMatchers("/level3/**").hasRole("vip3");
    
          // 开启自动配置的登录功能
          // /login 请求来到登录页
          // /login?error 重定向到这里表示登录失败
          http.formLogin();
      }
        //定义认证规则
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
           
           //在内存中定义,也可以用jdbc的认证
           auth.inMemoryAuthentication()
                  .withUser("kuangshen").password("123456").roles("vip2","vip3")
                  .and()
                  .withUser("root").password("123456").roles("vip1","vip2","vip3")
                  .and()
                  .withUser("guest").password("123456").roles("vip1","vip2");
        }
        //但是如果直接这样传密码会报错,因为要求要将前段传过来的密码进行某种方式加密,否则无法登录。
        //修改后的方法
          auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
              .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
              .and()
              .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
              .and()
              .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
        }
    }
    
  3. 权限控制和注销

    • 开启自动配置注销的功能
    //定制请求的授权规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启自动配置的注销的功能
        // /logout 注销请求
        http.logout();
        //默认注销后跳回登录页面,若想注销后跳回首页
        http.logout().logoutSuccessUrl("/");
    }
    
    • 新的需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮,且不同的角色看到的页面是不一样的
    • 添加依赖
    <dependency>
       <groupId>org.thymeleaf.extras</groupId>
       <artifactId>thymeleaf-extras-springsecurity5</artifactId>
       <version>xxx</version>
    </dependency>
    
    <!--登录注销-->
    <div class="right menu">
    
       <!--如果未登录-->
       <div sec:authorize="!isAuthenticated()">
           <a class="item" th:href="@{/login}">
               <i class="address card icon"></i> 登录
           </a>
       </div>
    
       <!--如果已登录-->
       <div sec:authorize="isAuthenticated()">
           <a class="item">
               <i class="address card icon"></i>
              用户名:<span sec:authentication="principal.username"></span>
              角色:<span sec:authentication="principal.authorities"></span>
           </a>
       </div>
    
       <div sec:authorize="isAuthenticated()">
           <a class="item" th:href="@{/logout}">
               <i class="address card icon"></i> 注销
           </a>
       </div>
    </div>
    
    • 还有一个可能的问题就是默认防止csrf跨站请求伪造,因为会产生安全问题,可以将请求改为post表单提交,或者在spring security中关闭csrf功能,在配置中增加 http.csrf().disable();
    <!-- sec:authorize="hasRole('vip1')" -->
    <div class="column" sec:authorize="hasRole('vip1')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 1</h5>
                   <hr>
                   <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                   <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                   <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
    <div class="column" sec:authorize="hasRole('vip2')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 2</h5>
                   <hr>
                   <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                   <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                   <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
    <div class="column" sec:authorize="hasRole('vip3')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 3</h5>
                   <hr>
                   <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                   <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                   <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
  4. 记住我的功能

    //在配置中增加,作用就是加了一个cookie,默认保留14天
    http.rememberMe();
    //定制登录页,toLogin页面是我们自己写的登录页面
    http.formLogin().loginPage("/toLogin");
    //请求的验证处理
    http.formLogin()
      .usernameParameter("username")
      .passwordParameter("password")
      .loginPage("/toLogin")
      .loginProcessingUrl("/login"); // 登陆表单提交请求
    //在前端登录页面增加夹住我的多选框,在后端进行验证处理
    http.rememberMe().rememberMeParameter("remember");
    
  5. 完整的配置

    package com.test.config;
    
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
       //定制请求的授权规则
       @Override
       protected void configure(HttpSecurity http) throws Exception {
    
           http.authorizeRequests().antMatchers("/").permitAll()
          .antMatchers("/level1/**").hasRole("vip1")
          .antMatchers("/level2/**").hasRole("vip2")
          .antMatchers("/level3/**").hasRole("vip3");
    
    
           //开启自动配置的登录功能:如果没有权限,就会跳转到登录页面!
               // /login 请求来到登录页
               // /login?error 重定向到这里表示登录失败
           http.formLogin()
              .usernameParameter("username")
              .passwordParameter("password")
              .loginPage("/toLogin")
              .loginProcessingUrl("/login"); // 登陆表单提交请求
    
           //开启自动配置的注销的功能
               // /logout 注销请求
               // .logoutSuccessUrl("/"); 注销成功来到首页
    
           http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
           http.logout().logoutSuccessUrl("/");
    
           //记住我
           http.rememberMe().rememberMeParameter("remember");
      }
    
       //定义认证规则
       @Override
       protected void configure(AuthenticationManagerBuilder auth) throws Exception {
           //在内存中定义,也可以在jdbc中去拿....
           //Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
           //要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
           //spring security 官方推荐的是使用bcrypt加密方式。
    
           auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                  .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
                  .and()
                  .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                  .and()
                  .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
      }
    }
    
posted @ 2024-05-18 09:51  Hanyta  阅读(7)  评论(0编辑  收藏  举报