一、创建项目
1、创建Spring Boot项目
配置pom文件
<!--Spring Boot WEB依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Spring Boot 测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring Boot MyBatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<!--数据库驱动依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
2、配置数据库和MyBatis
(1)初始化数据库并配置开发环境
数据库直接用图形化工具导入sql文件,设置当前的环境为开发环境
# 设置当前的环境为开发环境
spring:
profiles:
active: dev
application-dev.yml文件:
#设置项目端口号
server:
port: 9081
#数据库环境配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/coolshark?useSSL=false&serverTimeZone=Asia/Shanghai
username: root
password: root
#日志级别
logging:
level:
cn.highedu.coolshark: debug
(2)配置MyBatis接口扫描
在application.yml中添加扫描
# 设置当前的环境为开发环境
spring:
profiles:
active: dev
#mybatis设置 驼峰表示
mybatis:
mapper-locations: classpath:mappers/*.xml
configuration:
map-underscore-to-camel-case: true
3、使用Lombok
使用Lombok提供的注解,它不仅可以简化日志的创建,还可以提供许多其他简化编程的注解。
Lombok提供了一些常用的注解,如@Getter、@Setter、@ToString、@EqualsAndHashCode等。使用这些注解可以自动生成相应的代码。例如,使用@Getter注解可以自动生成属性的Getter方法,使用@Setter注解可以自动生成属性的Setter方法,使用@ToString注解可以自动生成toString方法等。
(1)使用步骤
- 安装Lombok插件:在IntelliJ IDEA中安装Lombok插件。打开File->Settings->Plugins,在搜索栏中输入Lombok,然后点击Install安装Lombok插件。
- 添加Lombok依赖:在Maven或Gradle的pom.xml文件中添加Lombok的依赖。
- 在Java类中使用Lombok注解:在Java类中使用Lombok注解来简化代码,例如使用@Data注解自动生成Getter、Setter、toString、equals、hashCode等方法。
- 在IDEA中开启Lombok支持:在IDEA中打开File->Settings->Build,Execution,Deployment->Compiler->Annotation Processors,勾选Enable annotation processing选项,然后在下方的Processor path中选择Lombok的jar包路径。
- 清除缓存:在IDEA中清除缓存,打开File->Invalidate Caches / Restart。
添加依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
在测试类中使用注解:(以后不用再创建logger,直接添加注解即可)
@SpringBootTest
@Slf4j
public class DataSourceTest {
//注入数据源 spring 帮我们去生成的
@Autowired(required = false)
private DataSource dateSource;
@Test
public void getConnect() throws SQLException {
log.info("获取数据库连接测试");
log.info("数据库连接:{}", dateSource.getConnection());
log.info("获取数据库连接成功");
}
}
创建User实体示例:
@Data //类中所有的属性自动生成getter、setter、toString等方法
@AllArgsConstructor //包含所有参数的构造方法
@NoArgsConstructor //生成无参构造
public class User {
private Long id;
private String name;
private Integer age;
}
测试类:
@SpringBootTest
@Slf4j
public class LombokTest {
@Test
public void createUser() {
User user1 = new User();
user1.setId(1L);
user1.setName("Tom");
user1.setAge(20);
log.info("user1:{}", user1);
User user2 = new User(2L, "Jerry", 20);
log.info("user2:{}", user2);
}
}
(2)Lombok的缺点
- 工具支持:Lombok依赖于编译时代码生成技术,因此在一些IDE或工具链不支持的情况下,可能会存在一些问题。
- 潜在风险:Lombok生成的代码可能会影响IDE的代码分析能力,可能会隐藏代码缺陷和潜在的问题,需要开发者仔细检查和测试。
- 不利于团队协作:Lombok会生成大量的代码,可能会导致代码库的混乱和难以阅读,不利于团队协作和代码维护。
(3)Lombok的全部注解
- @Data:注解在类上,自动为类生成getter、setter、toString、equals、hashCode等方法。
- @Getter:注解在属性上,自动生成getter方法。
- @Setter:注解在属性上,自动生成setter方法。
- @ToString:注解在类上,自动生成toString方法。
- @EqualsAndHashCode:注解在类上,自动生成equals和hashCode方法。
- @NoArgsConstructor:注解在类上,自动生成无参构造方法。
- @AllArgsConstructor:注解在类上,自动生成全参构造方法。
- @RequiredArgsConstructor:注解在类上,自动生成构造方法,只对final或@NonNull属性生效。
- @Builder:注解在类上,自动生成builder方法。
- @Log:注解在类上,自动生成Logger对象。
- @Log4j2:注解在类上,自动生成Log4j2 Logger对象。
- @Slf4j:注解在类上,自动生成Slf4j Logger对象。
- @Cleanup:注解在局部变量上,自动为局部变量调用close或者cleanup方法。
- @SneakyThrows:注解在方法上,将方法中的异常转化为unchecked异常。
- @Synchronized:注解在方法上,将方法转化为同步方法。
- @NonNull:注解在参数和属性上,表示参数和属性不能为空。
- @Nullable:注解在参数和属性上,表示参数和属性可以为空。
- @Value:注解在类上,与@Data类似,不过它会生成一个不可变的类。
- @Delegate:注解在属性上,将该属性的调用转发到指定对象上。
- @UtilityClass:注解在类上,表示该类是一个工具类,自动为类添加私有构造方法和静态方法。
二、Spring Security框架
1、使用SpringSecurity进行权限控制
其提供了一系列的功能用于保护Java Web应用程序,防止未经授权的访问
Spring Security 还提供了其他一些重要的功能和扩展,如:
- 基于注解的安全性:通过 Spring Security 的注解,可以为应用程序中的方法、类、参数等设置安全性规则,以便在运行时实施安全策略。
- CSRF(跨站请求伪造)保护:Spring Security 提供了一些内置的安全措施,以防止跨站点攻击,如 CSRF 保护、Clickjacking 防御、安全 HTTP 标头等。
- 单点登录(SSO):Spring Security 提供了与许多 SSO 解决方案集成的能力,如 CAS、OAuth2、OpenID Connect 等,以便为多个应用程序提供一致的身份验证和授权机制。
- 集成Spring框架:Spring Security 可以与 Spring 框架的其他模块和组件无缝集成,如 Spring MVC、Spring Boot、Spring Data 等,以便更方便地构建和维护安全的 Web 应用程序。
(1)认证和授权
认证是确定用户、设备或系统的身份是否真实
授权是决定哪些身份可以访问那些资源的过程
(2)Spring Security 使用步骤
1、 添加 Spring Security 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、配置安全规则
Spring Security配置可以分为两个主要方面:认证规则和授权规则。
认证规则确定了用户如何登录到应用程序。你可以配置基本的用户名和密码认证规则,也可以定义自定义认证规则。
授权规则决定了哪些用户可以访问应用程序的哪些部分。这包括Web请求的授权和方法级别的授权。
2、Spring Security认证
(1)配置临时认证规则
在dev.yml中添加配置
#设置项目端口号
server:
port: 9081
#数据库环境配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/coolshark?useSSL=false&serverTimeZone=Asia/Shanghai
username: root
password: root
#配置认证的用户名和密码
security:
user:
name: tom
password: 123456
#日志级别
logging:
level:
cn.highedu.csmall: debug
(2)配置密码加密
密码加密技术是一种将密码转换成不可逆的、难以破解的密文的方法,以保证用户密码的安全性。以下是一些主要的密码加密技术:
- MD5(Message Digest Algorithm 5):一种广泛使用的密码哈希函数,将任意长度的输入(明文)通过哈希算法,输出固定长度的哈希值(密文),不可逆。
- SHA-2(Secure Hash Algorithm 2):SHA-2 包含多个算法,比如 SHA-256,SHA-384 和 SHA-512,用于计算信息的哈希值,是一种更安全的哈希算法,比 MD5 更难以破解。
- BCrypt:一种基于 Blowfish 加密算法的密码哈希函数,加密后的密文长度固定为 60 个字符,可以设置迭代次数,防止暴力破解。
- PBKDF2(Password-Based Key Derivation Function 2):一种基于密码的密钥派生函数,可以根据一个密码和一个盐生成密钥,提高密码的安全性。
/**
* 设置密码加密规则
*/
@Configuration //声明spring管理类
@Slf4j
public class PasswordEncoderConfig {
@Bean
public PasswordEncoder passwordEncoder() {
//密码生成器
PasswordEncoder passwordEncoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
log.info("创建密码生成器:{}", passwordEncoder.getClass().getName());
return passwordEncoder;
}
}
测试类:
@SpringBootTest
@Slf4j
public class PasswordEncoderTest {
@Autowired
private PasswordEncoder passwordEncoder;
@Test
public void encoder(){
String password = "123456";
String encodePassword = passwordEncoder.encode(password);
log.info("密码明文:{}",password);
log.info("密码密文:{}",encodePassword);
}
}
测试结果:
: 创建密码生成器:org.springframework.security.crypto.password.DelegatingPasswordEncoder
: Adding welcome page: class path resource [static/index.html]
: Started PasswordEncoderTest in 1.732 seconds (process running for 2.511)
: 密码明文:123456
: 密码密文:{bcrypt}$2a$10$FMA8Sa3E/VZKRUhxnGoDpu7j5sEQRg8WqymLtPpf5r2/vM1ApdHGm
(3)提供数据进行认证
Spring Security 提供了基于程序提供的认证数据存储方式,需要用户实现 UserDetailsService 接口和 UserDetails 接口。
UserDetailsService 接口用于获取用户的认证信息
UserDetails 接口则用于描述用户的具体信息,如用户名、密码、用户角色等等。
(4)实现用户信息接口
实现UserDetails接口
/**
* 存储用户信息
* 返回用户信息详情(用户名、密码、权限)
*/
public class TestUserDetail implements UserDetails {
//定义用户名和密码
private String username = "tom";
private String password = "{bcrypt}$2a$10$FMA8Sa3E/VZKRUhxnGoDpu7j5sEQRg8WqymLtPpf5r2/vM1ApdHGm";
/**
* 返回用户的权限 如果返回null 表明用户没有任何权限
* 用户tom具有admin和user两个角色,同时具有查询和添加数据的权限
*
* @return 权限的集合
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
//添加角色
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
//添加权限
authorities.add(new SimpleGrantedAuthority("sys:log:query")); //查询日志的权限
authorities.add(new SimpleGrantedAuthority("sys:log:add"));//添加日志的权限
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
/**
* 返回false表示用户过期
*
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 用户是否被锁定 返回false表示用户不被锁定
*
* @return
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 以下方法返回false,表示用户凭证已过期
*
* @return true
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
实现 UserDetailsService接口:
/**
* 获取用户信息
*/
@Component
@Slf4j
public class TestUserDetailService implements UserDetailsService {
/**
* 根据用户名查询用户详情信息
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username.equals("tom")) {
log.info("用户名tom存在,准备返回信息");
return new TestUserDetail();
}
throw new UsernameNotFoundException("用户名:" + username + "不存在");
}
}
3、 Spring Security方法授权
(1)授权信息
Spring Security 的授权功能用于管理用户对资源的权限,它基于角色和权限来控制对方法和Web资源的访问。
Spring Security 授权功能允许你控制哪些用户可以访问哪些资源,以及哪些方法可以被哪些用户访问。
(2)【案例】添加角色和权限
/**
* 返回用户的权限 如果返回null 表明用户没有任何权限
* 用户tom具有admin和user两个角色,同时具有查询和添加数据的权限
*
* @return 权限的集合
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
//添加角色
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
//添加权限
authorities.add(new SimpleGrantedAuthority("sys:log:query")); //查询日志的权限
authorities.add(new SimpleGrantedAuthority("sys:log:add"));//添加日志的权限
return authorities;
}
(3)方法角色授权
Spring Security 提供方法级别的角色授权,用于保护应用程序中的方法,以防止未经授权的访问。通过在方法级别配置角色授权,你可以确保只有拥有特定角色的用户才能访问受保护的方法。这有助于保护应用程序中的关键功能和数据,确保只有授权用户可以访问和修改。
创建管理类,开启方法授权:
@Configuration
@EnableMethodSecurity //开启方法授权(5.7以及以后的版本)
//@EnableGlobalMethodSecurity(prePostEnabled = true) //spring 5.7之前的版本开启授权
public class MethodSecurityConfig {
}
做service:
@Service
@Slf4j
public class LogService {
/**
* 管理员日志方法 必须具有管理员角色才能访问
*
* @PreAuthorize 表示方法授权
* hasRole检查用户是否具有角色
*/
@PreAuthorize("hasRole('ADMIN')") //有管理员角色才能访问
public void adminLog() {
log.info("管理员日志方法");
}
/**
* 经理日志方法 必须具有经理角色才能访问
*/
@PreAuthorize("hasRole('MANAGER')")
public void managerLog() {
log.info("经理日志方法");
}
}
controller层:
@RestController
@Slf4j
public class LoggerController {
@Autowired
private LogService logService;
/**
* 访问请求admin/log 必须具有ADMIN角色
*
* @return
*/
@GetMapping("/admin/log")
public String adminLog() {
log.info("请求到达/admin/log");
logService.adminLog();
return "管理员查询了日志";
}
/**
* 访问请求/manager/log 必须具有manager角色才能访问
* @return
*/
@GetMapping("/manager/log")
public String managerLog() {
log.info("请求到达/manager/log");
logService.managerLog();
return "经理查询了日志";
}
}
测试效果:
(4)方法权限授权
一个角色的范围往往是很大的,一个用户可以分配多个角色。
权限控制往往不变
在LogService中添加方法(对权限进行操作):
/**
* 具有日志查询权限的用户才能访问
*/
@PreAuthorize("hasAnyAuthority('sys:log:query')")
public void queryList() {
log.info("日志查询方法");
}
@PreAuthorize("hasAuthority('sys:log:delete')")
public void delete() {
log.debug("日志删除方法");
}
控制器中定义访问这两个方法的入口:
@GetMapping("/log/query")
public String queryList(){
log.info("请求到达:/log/query");
logService.queryList();
return "查询了日志";
}
@GetMapping("/log/delete")
public String delete(){
log.info("请求到达:/log/delete");
logService.delete();
return "删除了日志";
}
4、Web资源授权
(1)Web授权原理
Spring Security 提供了 Web 资源保护功能,它通过一系列的 Web 过滤器来实现 。这些过滤器可以拦截所有的 Web 请求,并根据配置来进行安全处理。
(2)HTTP和Web授权配置
configure(HttpSecurity http) 方法用于配置过滤器链的规则,你可以在这里设置哪些 URL 需要授权以及授权的方式等。
configure(WebSecurity web) 方法可以配置绕过过滤器链的规则,比如设置哪些 URL 不需要被 Spring Security 保护。
从 Spring Security 5.7 开始,已经弃用了继承 WebSecurityConfigurerAdapter 的方式,而是采用了创建 SecurityFilterChain 类型的 Bean 来配置 Web 安全
配置管理类;
@Configuration
@EnableWebSecurity //开启web资源授权
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// /admin/index.html资源具有admin角色才能访问
http.authorizeHttpRequests()
.requestMatchers("/admin/index/html").hasRole("ADMIN");
http.authorizeHttpRequests()
.requestMatchers("/manager/index.html").hasRole("MANAGER");
return http.build();
}
}
测试效果展示:
(3)Web权限匹配模式
在一个网站项目中,可能会有数以千计的不同的URL请求,使用URL匹配模式可以大大简化授权配置的工作。
Spring Security 引入了 Ant 路径匹配,以便用户可以使用通配符( 和 *)来匹配请求 URL 的路径:
* 用于匹配路径中的单个字符或单个路径,例如 /user/* 可以匹配 /user/list 或 /user/edit,但不能匹配 /user/list/info。
用于匹配路径中的多个字符或多个路径,例如 /user/ 可以匹配 /user/list、/user/edit 和 /user/list/info。:
一般情况下都是两个*
@Configuration
@EnableWebSecurity //开启web资源授权
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
//所有资源不需要登录都可以访问
http.authorizeHttpRequests()
.requestMatchers("/static/**", "/css/**", "/js/**").permitAll();
// /admin/index.html资源具有admin角色才能访问
http.authorizeHttpRequests()
.requestMatchers("/admin/index.html").hasRole("ADMIN");
http.authorizeHttpRequests()
.requestMatchers("/manager/index.html").hasRole("MANAGER");
http.authorizeHttpRequests()
.requestMatchers("/user/index.html").hasRole("USER");
//其他资源需要登录就可以访问
http.authorizeHttpRequests().anyRequest().authenticated();
http.formLogin().permitAll();//放开其他资源
return http.build();
}
}
除了 hasRole,Spring Security 还提供了以下一些方法用于授权:
- hasAnyRole:判断当前用户是否拥有其中一个角色
- hasAuthority:判断当前用户是否拥有某个权限
- hasAnyAuthority:判断当前用户是否拥有其中一个权限
- authenticated:判断当前用户是否已经认证,即是否已经登录
- permitAll:允许所有用户访问
- denyAll:拒绝所有用户访问
- anonymous:允许匿名用户访问
- rememberMe:允许通过 remember-me 自动登录的用户访问
(4)绕过安全过滤器
Spring Security 的 Web 授权功能是由一系列过滤器共同完成的。在上述配置中,虽然对路径 "/static/**" 使用了 permitAll() 来放行请求,但这些请求仍然会经过一系列安全过滤器的处理,这可能会对性能产生一定的影响。
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
// /static/**、/css/**、/js/** 路径不需要认证, 即绕过认证过滤器
return (web) -> web.debug(true).ignoring().requestMatchers("/static/**", "/css/**", "/js/**");
}