目录
前言
特点
快速开始
导入依赖
运行项目
访问服务
权限控制
实现UserDetails接口
添加SecurityConfig配置类
测试接口DemoController
结果分析
总结
前言
Spring Security是一个强大且高度可定制的身份验证和访问控制框架。它是保护基于Spring的应用程序的事实标准。
Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring Security的真正力量在于它可以多么容易地扩展以满足自定义需求。
特点
- 对身份验证和授权的全面且可扩展的支持
- 防止会话固定、点击劫持、跨站点请求伪造等攻击
- Servlet API集成
- 与Spring Web MVC的可选集成
快速开始
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
运行项目
查看控制台的输出,会发现出现了警告。
警告翻译:
使用生成的安全密码:e3e4d1a9-2520-49a8-bb0b-359c2ed19314
此生成的密码仅供开发使用。在生产环境中运行应用程序之前,必须更新您的安全配置。
因为我们只是引入了SpringSecurity的依赖,并没有对其进行配置。所以此时使用的都是默认的配置,这些配置都是可以自定义的。
访问服务
访问后会跳转到登录页面,默认用户名user,密码在控制台中查看。默认的登录请求为/login,只有登录成功后才能继续访问。
输入用户名和密码,会跳转页面。但是我们没有设置登录成功后的页面跳转,所以结果是404 Not Found。其实我们没有必要去设置这个跳转页面,因为开发都是基于前后端分离的模式。前端发起登录请求,我们后端响应结果就行了。也就意味着这个登录页面也是多余的,后面我们会将这个登录禁用。
到这里就是对SpringSecurity的快速开始,接下来我们来看对权限的控制。
权限控制
实现UserDetails接口
SpringSecurity需要通过实现了UserDetails接口的类来判断用户登录和权限控制,我们要做的就是查询用户信息,然后封装成UserDetails对象并交给Security进行处理。
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class SysUser implements UserDetails {
private final String username;
private final String password;
private final Collection<? extends GrantedAuthority> authorities;
public SysUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
this.username = username;
this.password = password;
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
// 是否账号未过期
return true;
}
@Override
public boolean isAccountNonLocked() {
// 是否账号未锁定
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// 是否凭据未过期
return true;
}
@Override
public boolean isEnabled() {
// 是否账号可用
return true;
}
}
添加SecurityConfig配置类
密码编码器:必须指定密码编码器,因为密码不允许明文存储。账号的密码为123abc,但存储的密码可不是123abc,而是经过编码后生成的一串字符串。
添加用户到内存:这里就直接添加用户到内存,正常是要保存在数据库里。道理其实是一样的,都是要提供给Security封装实现了UserDetails接口的类。
配置过滤器链:这个是很重要的配置,Security的扩展性很强,就是因为可以在这里配置各种自定义的设置。例如,我们可以配置自定义身份验证过滤器,从而替换默认的配置。
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.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// 添加用户到内存
@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
String password = "123abc";
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String encode = bCryptPasswordEncoder.encode(password);
SysUser sysUser = new SysUser("艾伦", encode,
AuthorityUtils.commaSeparatedStringToAuthorityList("权限1,权限2"));
return new InMemoryUserDetailsManager(sysUser);
}
// 密码编码器
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 配置过滤器链
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
// 关闭跨域漏洞防御
httpSecurity.csrf(AbstractHttpConfigurer::disable);
return httpSecurity.build();
}
}
测试接口DemoController
我们编写两个接口,用来测试权限控制。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/test1")
public String demo1() {
System.out.println("test1访问成功!");
return "test1访问成功!";
}
@GetMapping("/test2")
public String demo2() {
System.out.println("test2访问成功!");
return "test2访问成功!";
}
}
设置权限控制authorizeHttpRequests
我们的用户只有权限1和权限2,并没有权限3。也就意味着demo1接口我们能正常访问,而demo2接口会因为没有权限访问失败。
注意:这里要指定登录请求为/login,否则会被拒绝访问。
// 配置过滤器链
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
.requestMatchers(HttpMethod.GET, "/test1").hasAnyAuthority("权限1", "权限2")
.requestMatchers(HttpMethod.GET, "/test2").hasAuthority("权限3")
);
httpSecurity.formLogin(formLogin -> formLogin
.loginProcessingUrl("/login") // 登录请求
);
// 关闭跨域漏洞防御
httpSecurity.csrf(AbstractHttpConfigurer::disable);
return httpSecurity.build();
}
结果分析
结果就是/test1访问成功,而/test2因为没有权限访问失败。
/test1
/test2
总结
这就是对SpringSecurity的初识,先做一个了解。要想在项目中整合SpringSecurity的话,还需要进一步学习,了解更深层的原理。
《整合SpringSecurity》
https://blog.csdn.net/qq_74312711/article/details/134992609?spm=1001.2014.3001.5502