🐛 用户Mapper判断写错
This commit is contained in:
parent
44732e6352
commit
84a053fdb6
|
@ -341,3 +341,139 @@ public UserDetails getCurrentUserDetail() {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## URL资源认证配置
|
||||
|
||||
### 角色与权限配置
|
||||
|
||||
#### 1. 基于角色的URL访问控制
|
||||
|
||||
##### 单角色配置
|
||||
|
||||
配置`/api/**`路径下的所有接口需要`ADMIN`角色才能访问:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
// 注意:会自动添加"ROLE_"前缀,实际检查的是ROLE_ADMIN
|
||||
.requestMatchers("/api/**").hasRole("ADMIN")
|
||||
)
|
||||
// 其他配置...
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
```
|
||||
|
||||
##### 多角色配置(满足任一角色即可访问)
|
||||
|
||||
```java
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
// 检查是否有ADMIN或USER角色(自动添加ROLE_前缀)
|
||||
.requestMatchers("/api/**").hasAnyRole("ADMIN", "USER")
|
||||
)
|
||||
// 其他配置...
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 基于权限的URL访问控制
|
||||
|
||||
##### 需要所有指定权限
|
||||
|
||||
```java
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
// 需要同时拥有"all"和"read"权限
|
||||
.requestMatchers("/api/**").hasAuthority("all")
|
||||
.requestMatchers("/api/**").hasAuthority("read")
|
||||
)
|
||||
// 其他配置...
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
```
|
||||
|
||||
##### 满足任一权限即可
|
||||
|
||||
```java
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
// 拥有"all"或"read"任一权限即可访问
|
||||
.requestMatchers("/api/**").hasAnyAuthority("all", "read")
|
||||
)
|
||||
// 其他配置...
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
```
|
||||
|
||||
### 综合配置策略
|
||||
|
||||
#### 1. 基本配置模式
|
||||
|
||||
```java
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
// 特定路径需要认证
|
||||
.requestMatchers("/api/**").authenticated()
|
||||
// 其他请求全部放行
|
||||
.anyRequest().permitAll()
|
||||
)
|
||||
// 其他配置...
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 多路径匹配配置
|
||||
|
||||
```java
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// 定义无需认证的白名单路径
|
||||
String[] permitAllUrls = {
|
||||
"/", "/doc.html/**",
|
||||
"/webjars/**", "/images/**",
|
||||
"/.well-known/**", "/favicon.ico",
|
||||
"/error/**", "/swagger-ui/**",
|
||||
"/v3/api-docs/**"
|
||||
};
|
||||
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
// API路径需要认证
|
||||
.requestMatchers("/api/**").authenticated()
|
||||
// 白名单路径直接放行
|
||||
.requestMatchers(permitAllUrls).permitAll()
|
||||
// 其他请求需要登录(非匿名访问)
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
// 其他配置...
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
```
|
||||
|
||||
### 重要说明
|
||||
|
||||
1. **角色与权限的区别**:
|
||||
- `hasRole()`会自动添加"ROLE_"前缀
|
||||
- `hasAuthority()`直接使用指定的权限字符串
|
||||
2. **匹配顺序**:
|
||||
- Spring Security会按照配置的顺序进行匹配
|
||||
- 更具体的路径应该放在前面,通用规则(如anyRequest)放在最后
|
||||
3. **方法选择建议**:
|
||||
- `hasRole()`/`hasAnyRole()`:适合基于角色的访问控制
|
||||
- `hasAuthority()`/`hasAnyAuthority()`:适合更细粒度的权限控制
|
||||
- `authenticated()`:只需认证通过,不检查具体角色/权限
|
||||
- `permitAll()`:完全开放访问
|
||||
4. **最佳实践**:
|
||||
- 对于REST API,通常使用`authenticated()`配合方法级权限控制
|
||||
- 静态资源应明确配置`permitAll()`
|
||||
- 生产环境不建议使用`anyRequest().permitAll()`
|
|
@ -2,6 +2,8 @@ package com.spring.step2.security.config;
|
|||
|
||||
import com.spring.step2.security.handler.SecurityAccessDeniedHandler;
|
||||
import com.spring.step2.security.handler.SecurityAuthenticationEntryPoint;
|
||||
import com.spring.step2.security.service.DbUserDetailService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
|
@ -13,27 +15,21 @@ import org.springframework.security.web.SecurityFilterChain;
|
|||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityWebConfiguration {
|
||||
|
||||
private final DbUserDetailService dbUserDetailService;
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
String[] permitAllUrls = {
|
||||
"/", "/doc.html/**",
|
||||
"/webjars/**", "/images/**", ".well-known/**", "favicon.ico", "/error/**",
|
||||
"/swagger-ui/**", "/v3/api-docs/**"
|
||||
};
|
||||
|
||||
http.authorizeHttpRequests(authorizeRequests ->
|
||||
// 访问路径为 /api 时需要进行认证
|
||||
authorizeRequests
|
||||
.requestMatchers(permitAllUrls).permitAll()
|
||||
// .requestMatchers("/api/**").hasAnyRole("Admin", "ADMIN", "admin")
|
||||
// 只认证 /api/** 下的所有接口
|
||||
.requestMatchers("/api/**").authenticated()
|
||||
// 其余请求都放行
|
||||
.anyRequest().permitAll()
|
||||
// .requestMatchers("/api/security/**").permitAll()
|
||||
// .requestMatchers(HttpMethod.GET, "/api/anonymous/**").anonymous()
|
||||
// // 会自动变成 ROLE_ADMIN
|
||||
// // .requestMatchers("/api/**").hasRole("ADMIN")
|
||||
// .requestMatchers("/api/**").hasAnyAuthority("all", "read")
|
||||
)
|
||||
.formLogin(loginPage -> loginPage
|
||||
// 自定义登录页路径
|
||||
|
@ -56,9 +52,12 @@ public class SecurityWebConfiguration {
|
|||
)
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.exceptionHandling(configurer -> configurer
|
||||
// 自定无权访问返回内容
|
||||
.accessDeniedHandler(new SecurityAccessDeniedHandler())
|
||||
// 自定义未授权返回内容
|
||||
.authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
|
||||
)
|
||||
.userDetailsService(dbUserDetailService)
|
||||
;
|
||||
|
||||
return http.build();
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.spring.step2.security.handler;
|
|||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.spring.step2.domain.vo.result.Result;
|
||||
import com.spring.step2.domain.vo.result.ResultCodeEnum;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
@ -17,8 +18,10 @@ public class SecurityAccessDeniedHandler implements AccessDeniedHandler {
|
|||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
|
||||
log.error("CustomerAccessDeniedHandler:{}", accessDeniedException.getLocalizedMessage());
|
||||
|
||||
Result<Object> result = Result.error(accessDeniedException.getMessage());
|
||||
// 无权访问接口
|
||||
Result<Object> result = Result.error(accessDeniedException.getMessage(), ResultCodeEnum.FAIL_NO_ACCESS_DENIED);
|
||||
|
||||
// 转成JSON格式
|
||||
Object json = JSON.toJSON(result);
|
||||
|
||||
// 返回响应
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.spring.step2.security.handler;
|
|||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.spring.step2.domain.vo.result.Result;
|
||||
import jakarta.servlet.ServletException;
|
||||
import com.spring.step2.domain.vo.result.ResultCodeEnum;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -15,11 +15,13 @@ import java.io.IOException;
|
|||
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
|
||||
log.error("CustomerAccessDeniedHandler:{}", authException.getLocalizedMessage());
|
||||
|
||||
Result<Object> result = Result.error(authException.getMessage());
|
||||
// 未认证---未登录
|
||||
Result<Object> result = Result.error(authException.getMessage(), ResultCodeEnum.LOGIN_AUTH);
|
||||
|
||||
// 将错误的请求转成JSON
|
||||
Object json = JSON.toJSON(result);
|
||||
|
||||
// 返回响应
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.spring.step2.security.service;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.spring.step2.domain.entity.PermissionEntity;
|
||||
import com.spring.step2.domain.entity.UserEntity;
|
||||
import com.spring.step2.mapper.UserMapper;
|
||||
|
@ -13,6 +14,7 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
@DS("testJwt")
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DbUserDetailService implements UserDetailsService {
|
||||
|
|
|
@ -51,8 +51,8 @@
|
|||
<include refid="Base_Column_List"/>
|
||||
from t_user
|
||||
<where>
|
||||
<if test="username != null and username != ;;">
|
||||
username=#{username}
|
||||
<if test="username != null and username != null">
|
||||
username = #{username}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
|
Loading…
Reference in New Issue