【SpringSecurity】快速入门—通俗易懂

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 【SpringSecurity】快速入门—通俗易懂


1.导入依赖

首先,在pom.xml文件中添加Spring Security依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

2.继承WebSecurityConfigurerAdapter

创建一个WebSecurityConfig类,继承WebSecurityConfigurerAdapter:

继承WebSecurityConfigurerAdapter是因为我们要重写里面的方法 定义一些安全配置 例如:注销

功能、访问控制、登录页面等。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

protected void configure(HttpSecurity http)这个方法用于配置拦截保护的HTTP请求 配置HTTP安

全性 定义哪些URL应该受到保护 哪些用户可以访问哪些URL 以及保护的URL应该执行哪些安全措

@Override
  protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
      //.loginPage("/login.html")//指定登录页面(这里不会前端,所以不写页面了)
      //.loginProcessingUrl("/authentication/form")//登录访问路径(登录页面的form表单提交路径)
      //.failureUrl("/error.html")//用户名或密码错误访问的页面
      //.usernameParameter("username")
      //.passwordParameter("password")   //要认证的 用户名, 密码  的参数名,默认username, password
      .defaultSuccessUrl("/index/toIndex").permitAll()//defaultSuccessUrl:登录成功后,是否始终跳转到登录成功url,它默认为false。  permitAll()就是指不需要拦截
    .and().authorizeRequests()
      .antMatchers("/index/testRoleAndPermission").hasAnyRole("admin")//设置哪些路径需要什么权限
      .antMatchers("/index/anyOne","/index/anyTwo").permitAll()//设置哪些路径可以直接访问,不需要认证
      .anyRequest().authenticated();//其余任何请求都需要认证
    .and().csrf()
      .disable();//关闭csrf防护
  }

public void configure(AuthenticationManagerBuilder auth) 这个方法主要是配置 身份验证机制 就

是配置密码匹配器和用户从数据库查询用户的service

// 用于配置身份验证机制
        // AuthenticationManagerBuilder常用方法:(下面的方法我没有写参数,实际情况可能是有参的)
                // inMemoryAuthentication(): 这个方法允许您在内存中配置用户详细信息。您可以指定用户名、密码和用户角色。这对于快速测试和开发目的非常方便。
                // userDetailsService(): 这个方法接受一个UserDetailsService对象,用于加载用户的详细信息。UserDetailsService是一个接口,您需要实现它来根据用户名加载用户信息。
                // jdbcAuthentication(): 这个方法允许您使用JDBC来加载用户详细信息。您需要提供一个DataSource对象和相应的查询语句来检索用户名、密码和角色信息。
                // ldapAuthentication(): 这个方法用于配置LDAP(轻量级目录访问协议)身份验证。您需要提供LDAP服务器的连接信息和相应的查询语句。
                // authenticationProvider(): 这个方法允许您提供自定义的AuthenticationProvider实现,用于验证用户的身份。
    // userDetailsService(T userDetailsService):    根据传入的自定义UserDetailsService做身份验证。
    // 返回值:                                       会返回一个DaoAuthenticationConfigurer(该类继承AbstractDaoAuthenticationConfigurer抽象类)}
        // passwordEncoder(PasswordEncoder passwordEncoder): 来自于抽象类, 用于指定自定义密码匹配器,便于后续springsecutiry底层后续使用。
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
  }

public PasswordEncoder passwordEncoder() 这个是密码匹配器 SpringSecurity校验密码的时候

就要用到密码匹配器 对密码进行加密解密校验对比操作

// 必须要个这种密码匹配器,springsecurity要求的,必须对密码进行加密。
  @Bean
  public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
  }

3.实现UserDetailsService

客户端输入用户名和密码 后端必须要从数据库查询出数据 进行校验 需要实现UserDetailsService

重写查询校验方法

/**
 * @author lihao
 * @version 1.0
 * @ClassName SecurityUserServiceImpl
 * @date 2023/5/25  9:43
 * @apiNote UserDetailsService:用于加载用户的详细信息,以供身份验证和授权使用。它提供了一个方法loadUserByUsername(String username)用于用户名获取用户的详细信息。
 *                              我们想更改springcurity的认证,我们就可以实现UserDetailsService,因为security底层就是用其做核心认证的。
 **/
@Service
public class SecurityUserServiceImpl extends ServiceImpl<SecurityUserMapper, SecurityUser> implements SecurityUserService, UserDetailsService {
  
  @Resource
  private SecurityUserMapper securityUserMapper;
  
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    LambdaQueryWrapper<SecurityUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(SecurityUser::getUsername,username);
    SecurityUser user = securityUserMapper.selectOne(wrapper);
    if (user==null) {
      throw new UsernameNotFoundException("用户没找到");
    }
    
        // loadUserByUsername方法需要返回一个UserDetails(接口),常用实现类User。因此我们返回一个SpringSecurity提供的User对象。
        // 该User对象所需的参数中,密码必须加密(由springsecurity要求),因为我前面已经在SecurityConfig配置了加密器,所以这里就不需要对密码进行加密。
        // 否则需要加密:new BCryptPasswordEncoder().encode(user.getPassword())  ---- 可以这么写
    // 第三个参数,他需要一个权限集合,这里只做认证,所以随便搞一个角色集合,不影响认证,注意,这里第三个参数不能直接传null,必须给它一个集合。
    List<GrantedAuthority> adminAuthority = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
    return new User(user.getUsername(), user.getPassword(), adminAuthority); // 已在SecurityConfig配置了加密组件,所以不需要对这里的密码加密。
  }

4.记住我

客户端登录一次以后 下次访问不用登录 直接访问

需要在configure(HttpSecurity http)配置

// 开启记住我功能
http.rememberMe()
 .tokenRepository(tokenRepository)
 .userDetailsService(usersService);

.tokenRepository(tokenRepository):这是为"记住我"功能配置token存储库。token是用来存储

和验证用户会话信息的。这通常是一个在数据库或其他持久性存储中保存信息的对象。

.userDetailsService(usersService):这是为"记住我"功能配置用户详情服务。

UserDetailsService是Spring Security中的一个接口,它有一个方法loadUserByUsername,用于根

据用户名获取用户信息。usersService需要实现这个接口,并能够根据用户名找到用户的详细信

息。这对于"记住我"功能很重要,因为它需要知道用户的详细信息(例如他们的加密密码)以验证

他们的身份。

@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository persistentTokenRepository(){
 JdbcTokenRepositoryImpl jdbcTokenRepository = new 
JdbcTokenRepositoryImpl();
// 赋值数据源
jdbcTokenRepository.setDataSource(dataSource);
// 自动创建表,第一次执行会创建,以后要执行就要删除掉!
jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
 }
}

还可以设置有效期

5.用户注销

http.logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll
();
  1. http.logout(): 这是调用Spring Security的HTTP安全性配置的logout方法,它配置了用户的注销功能。
  2. .logoutUrl("/logout"): 这告诉Spring Security,当用户点击注销时,应该将他们重定向到URL "/logout"。这通常是应用程序的一个特殊页面,它执行注销操作并终止用户的会话。
  3. .logoutSuccessUrl("/index"): 当注销操作成功后,用户将被重定向到这个URL。在这个例子中,用户将被重定向到应用程序的"/index"页面。
  4. .permitAll(): 这告诉Spring Security,所有用户都应该能够访问注销功能。换句话说,它不限制谁可以注销,所有用户都可以。

总的来说,这段代码的目的是配置Spring Security的注销功能,使得所有用户都可以注销,并且当

他们注销成功后,他们将被重定向到应用程序的"/index"页面。

6.CSRF理解

跨站请求伪造 (英语: Cross-site request forgery ),也被称为 one-click

attack 或者 session riding ,通常缩写为 CSRF 或者 XSRF , 是一种挟制用户在当前已

登录的 Web 应用程序上执行非本意的操作的攻击方法。跟 跨网站脚本 XSS )相比, XSS

利用的是用户对指定网站的信任, CSRF 利用的是网站对用户网页浏览器的信任。

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个

自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买

商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。

这利用了 web 中用户身份验证的一个漏洞: 简单的身份验证只能保证请求发自某个用户的

浏览器,却不能保证请求本身是用户自愿发出的

Spring Security 4.0 开始,默认情况下会启用 CSRF 保护,以防止 CSRF 攻击应用

程序, Spring Security CSRF 会针对 PATCH POST PUT DELETE 方法进行防护。

开启CSRF后,Spring Security会添加一个CSRF令牌到表单提交的请求中,以确保只有合法的请

求才能被处理。这样可以防止攻击者通过注入恶意代码或跨站请求伪造等方式来篡改服务器资源。

7.注解功能

使用注解功能前 要先开启注解功能 在启动类加上@EnableGlobalMethodSecurity()注解 注解里面

要使用什么注解 就在括号里填写 xxx注解=true 例如:

@EnableGlobalMethodService(securedEnabled = true) 使用@securedEnabled注解

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled=true)
public class DemosecurityApplication {
public static void main(String[] args) {
 SpringApplication.run(DemosecurityApplication.class, args);
 }
}

7.1@Secured

判断是否具有这个角色 字符串前缀需要添加ROLE_

// 测试注解:
@RequestMapping("testSecured")
@ResponseBody
@Secured({"ROLE_normal","ROLE_admin"})
public String helloUser() {
return "hello,user";
}

7.2@PreAuthorized

先开启注解功能:

@EnableGlobalMethodSecurity (prePostEnabled = true )

@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用

户的 roles/permissions 参数传到方法中。

@RequestMapping("/preAuthorize")
@ResponseBody
//@PreAuthorize("hasRole('ROLE_管理员')")
@PreAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
 System.out.println("preAuthorize");
return "preAuthorize";
}

7.3@PostAuthorized

先开启注解功能:

@EnableGlobalMethodSecurity (prePostEnabled = true )

@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值

的权限 .

@RequestMapping("/testPostAuthorize")
@ResponseBody
@PostAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
 System.out.println("test--PostAuthorize");
return "PostAuthorize";
}

7.4@PostFilter

@PostFilter :权限验证之后对数据进行过滤 留下用户名是 admin1 的数据

表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素

@RequestMapping("getAll")
@PreAuthorize("hasRole('ROLE_管理员')")
@PostFilter("filterObject.username == 'admin1'")
@ResponseBody
public List<UserInfo> getAllUser(){
 ArrayList<UserInfo> list = new ArrayList<>();
 list.add(new UserInfo(1l,"admin1","6666"));
 list.add(new UserInfo(2l,"admin2","888"));
return list;
}

7.5Z@PreFilter

@PreFilter: 进入控制器之前对数据进行过滤

@RequestMapping("getTestPreFilter")
@PreAuthorize("hasRole('ROLE_管理员')")
@PreFilter(value = "filterObject.id%2==0")
@ResponseBody
public List<UserInfo> getTestPreFilter(@RequestBody List<UserInfo> 
list){
 list.forEach(t-> {
 System.out.println(t.getId()+"\t"+t.getUsername());
 });
return list;
}

8.原理解析

SpringSecurity本质:其实就是一个过滤器链,内部提供了各种功能的过滤器。springsecurity底层就是这些过滤器一层一层的执行帮我们实现的权限管理。

图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示。

UsernamePasswordAuthenticationFilter: 用于处理基于表单的登录请求,从表单中获取用户名和

密码。 默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name

值为 username 和 password。 这两个值可以通过设置这个过滤器的usernameParameter 和

passwordParameter 两个参数的值进行修改。 其内部还有 登录成功 或 失败后 进行处理的

AuthenticationSuccessHandler 和 AuthenticationFailureHandler,这些都可以根据需求做相关改

变。

ExceptionTranslationFilter: 处理 AccessDeniedException 和 AuthenticationException 异常。 3.

FilterSecurityInterceptor: 是用于保护web资源的,使用 AccessDecisionManager 对当前用户进

行授权访问。

SpringSecurity认证流程:

相关文章
|
7月前
|
安全 算法 Java
SpringSecurity 快速入门
SpringSecurity 快速入门
100 3
|
JSON Java Maven
Springboot2.0快速入门(第一章)
Springboot2.0快速入门(第一章)
|
7月前
|
安全 Java 数据安全/隐私保护
SpringSecurity6从入门到实战之引言和基本概念
《SpringSecurity6从入门到实战》介绍了Spring Security这一强大的Java安全框架,主要用于保护Spring应用程序的安全。它提供认证和授权功能,支持多种认证方式,并具备高度可定制性。文章阐述了权限管理的重要性,包括用户认证(验证用户身份)和用户授权(控制用户访问权限)。相较于其他如Shiro和Sa-Token的安全框架,Spring Security因与Spring生态的深度整合及对OAuth2的支持,常成为微服务项目的选择。
|
6月前
|
JavaScript 程序员 应用服务中间件
快速入门Web开发(上) 黑马程序员JavaWeb开发教程(2)
快速入门Web开发(上) 黑马程序员JavaWeb开发教程(2)
61 7
|
6月前
|
XML 存储 JavaScript
快速入门Web开发(上) 黑马程序员JavaWeb开发教程(1)
快速入门Web开发(上) 黑马程序员JavaWeb开发教程(1)
74 5
|
6月前
|
Java 程序员 应用服务中间件
程序员必知:Webflux快速入门
程序员必知:Webflux快速入门
199 0
|
6月前
|
Java 数据安全/隐私保护 Spring
SpringSecurity6从入门到实战之SpringSecurity快速入门
这篇文章是关于使用SpringSecurity 6进行快速入门的教程。首先介绍了所需的环境配置,包括SpringSecurity 6.0.8、SpringBoot 3.0.12和JDK 17。接着,通过步骤展示了如何创建一个新的SpringBoot工程,并添加Web支持。然后,运行工程并测试了Hello接口,确保其正常工作。之后,引入SpringSecurity依赖后,无需额外配置,系统即实现了基础的认证功能,自动重定向到登录页面。文章通过截图详细说明了这个过程,包括控制台日志、登录页面以及登录后的资源访问。
|
存储 SQL 前端开发
SpringSecurity-从入门到精通(2)
2.3.3.2 密码加密存储 ​ 实际项目中我们不会把密码明文存储在数据库中。 ​ 默认使用的PasswordEncoder要求数据库中的密码格式为:{id}password 。它会根据id去判断密码的加密方式。但是我们一般不会采用这种方式。 ​ 所以就需要替换 PasswordEncoder。
|
7月前
|
存储 安全 Java
SpringSecurity 从入门到精通
SpringSecurity 从入门到精通
|
存储 NoSQL Java
SpringSecurity-从入门到精通学习笔记2
SpringSecurity-从入门到精通学习笔记
56 0

相关实验场景

更多
下一篇
DataWorks