Spring Boot Security多用户同端点Basic认证实现方法
Spring Boot多用户Basic认证落地实现方案
核心改造逻辑
原有代码仅从配置读取单组账号写入内存,无法满足多用户分凭证认证需求,本次改造覆盖两个核心要求:
- 支持批量加载多组用户凭证,统一托管到Spring Security内存用户管理器
- 新增请求身份一致性校验,Basic认证通过的用户名必须和请求传入的
user参数匹配,避免跨用户越权访问 - 修正原配置中路径匹配规则和实际接口路径不匹配的问题
第一步:调整多用户配置结构
替换原单组账号密码配置,改用列表形式存储多用户凭证,以application.yml为例:
app: auth: users: - username: user01 password: pass01@2024 role: OPERATOR - username: user02 password: pass02@2024 role: OPERATOR - username: admin password: admin@2024 role: ADMIN
如果使用application.properties配置,写法如下:
app.auth.users[0].username=user01 app.auth.users[0].password=pass01@2024 app.auth.users[0].role=OPERATOR app.auth.users[1].username=user02 app.auth.users[1].password=pass02@2024 app.auth.users[1].role=OPERATOR app.auth.users[2].username=admin app.auth.users[2].password=admin@2024 app.auth.users[2].role=ADMIN
第二步:定义配置映射类
用于绑定配置文件中的多用户列表为Java对象:
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.List; @Component @ConfigurationProperties(prefix = "app.auth") public class AuthUserProperties { private List<UserAuthConfig> users; public List<UserAuthConfig> getUsers() { return users; } public void setUsers(List<UserAuthConfig> users) { this.users = users; } public static class UserAuthConfig { private String username; private String password; private String role; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } } }
如果项目已引入Lombok,可直接给类加@Data注解省略getter/setter方法
第三步:改造安全配置类
基于原有代码做逻辑替换,完整可运行代码如下:
import org.springframework.beans.factory.annotation.Autowired; 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.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import javax.servlet.http.HttpServletRequest; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AuthUserProperties authUserProperties; @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/").permitAll() // 匹配目标接口,绑定自定义身份校验规则 .antMatchers("/function/id/**").access("@userMatchValidator.check(request,authentication)") .antMatchers("/login/**").authenticated() .and() .httpBasic(); } @Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); // 循环加载所有配置的用户凭证 authUserProperties.getUsers().forEach(userConfig -> { String encodedPassword = passwordEncoder().encode(userConfig.getPassword()); manager.createUser(User.withUsername(userConfig.getUsername()) .password(encodedPassword) .roles(userConfig.getRole()) .build()); }); return manager; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 自定义校验逻辑:请求参数user必须和当前Basic认证的用户名一致 @Bean("userMatchValidator") public UserMatchValidator userMatchValidator() { return new UserMatchValidator(); } public static class UserMatchValidator { public boolean check(HttpServletRequest request, org.springframework.security.core.Authentication authentication) { if (authentication == null || !authentication.isAuthenticated()) { return false; } String requestUser = request.getParameter("user"); String currentAuthUser = authentication.getName(); return currentAuthUser.equals(requestUser); } } }
验证规则
- 访问
http://localhost:8080/function/id/?user=user01&id=xxx时,必须在Basic请求头中传入user01对应的正确密码,否则返回401 - 若使用user01的账号密码发起请求,但参数传入
user=user02,会直接返回403,拦截越权访问 - 后续新增、修改用户凭证只需要调整配置文件列表,不需要修改业务代码
内容的提问来源于stack exchange,提问作者Rose
相关产品推荐
相关产品推荐

