java - 如何在spring security中同时配置内存认证和jdbc认证
问题描述
我可以通过以下配置实现内存身份验证
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication().withUser("praveen").password("{noop}praveen@123#").roles("ADMIN");
auth.inMemoryAuthentication().withUser("vedanta").password("{noop}vedanta@123#").roles("USER");
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/resources/**", "/", "/login", "/api/**").permitAll()
.antMatchers("/app/admin/*").hasRole("ADMIN").antMatchers("/app/user/*")
.hasAnyRole("ADMIN", "USER")
.and().exceptionHandling().accessDeniedPage("/403")
.and().formLogin()
.loginPage("/login").usernameParameter("userName")
.passwordParameter("password")
.defaultSuccessUrl("/app/user/dashboard")
.failureUrl("/login?error=true")
.and().logout()
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.invalidateHttpSession(true)
.and().csrf().disable();
http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
}
}
并通过以下配置进行 jdbc 身份验证(在不同的项目中)
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
DataSource dataSource;
@Autowired
public void configureJdbcAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
.authoritiesByUsernameQuery(
"select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId where username = ?");
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/resources/**", "/", "/login")
.permitAll()
.antMatchers("/config/*", "/app/admin/*")
.hasRole("ADMIN")
.antMatchers("/app/user/*")
.hasAnyRole("ADMIN", "USER")
.antMatchers("/api/**")
.hasRole("APIUSER")
.and().exceptionHandling()
.accessDeniedPage("/403")
.and().formLogin()
.loginPage("/login")
.usernameParameter("userName").passwordParameter("password")
.defaultSuccessUrl("/app/user/dashboard")
.failureUrl("/login?error=true")
.and().logout()
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.invalidateHttpSession(true)
.and().httpBasic()
.and().csrf()
.disable();
http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
}
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
当我尝试在同一个项目中实现这两者时(我刚刚在我的 SpringSecurityConfig 中添加了 configureInMemoryAuthentication 和 configureJdbcAuthentication 方法,如下所示)
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
...
@Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("restapiuser")
.password("restapiuser@123#")
.roles("APIUSER");
}
@Autowired
public void configureJdbcAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
.authoritiesByUsernameQuery(
"select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId where username = ?");
}
...
}
但我无法使用 inMemoryAuthentication 凭据登录成功,我已被重定向到“/login?error=true”页面。
但我能够使用 jdbcAuthentication 凭据成功登录。
但不能两者兼得。
我做错什么了吗?
是否可以结合两个身份验证?
解决方案
错误是,身份验证管理器试图解码我的纯密码并发出此警告。
WARN - Encoded password does not look like BCrypt
在看到我尝试过的日志后password("{noop}restapiuser@123#")
也没有工作可能是因为 jdbcAuthentication 已为 passwordEncoder 注册,身份验证管理器每次都会尝试解密/解码密码。所以没有办法跳过密码解码需要提供编码密码。
由于我没有保留编码密码,它正在尝试对其进行解码并重定向到 failureUrl。
参考解决方案
@Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("restapiuser")
.password(new BCryptPasswordEncoder().encode("restapiuser@123#"))
.roles("APIUSER");
}
或者,最佳做法是保留编码密码而不是普通密码
.password("$2a$10$GRoNCbeVoBYMcZH7QLX2O.wWxkMtB4qiBY8y.XzvRN/mvktS9GWc6")
选择。只有一种 configureAuthentication 方法,但在内存和 jdbc 身份验证中都配置如下
@Autowired
public void configureBothAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("restapiuser")
.password(new BCryptPasswordEncoder().encode("restapiuser@123#"))
.roles("ADMIN");
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
.authoritiesByUsernameQuery(
"select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId where username = ?");
}
因此,
可以在 spring 项目中同时实现 InMemoryAuthentication 和 jdbcAuthentication。
推荐阅读
- python - 更改 IF 循环内的变量值
- amazon-web-services - AWS Certificate Manager,无法获取子域的 https
- php - 在 php 中设置首字母大写,但 ucfirst(strtolower('string')) 不起作用
- python - TypeError: ufunc 'add' 不包含签名匹配类型 dtype('
我是 Python 用户的初学者。当我尝试在下面编写代码时发生错误
import numpy as np np.array(['a', 'b', 'c']) + np.array(['d' ,'e', 'f'])
Type
- c# - 将 id 设置为模型中的对象名称以用于 rest api asp.net 核心
- asp.net-core - ASP Net Core 中的 RabbitMQ 通道生命周期和访问
- jenkins - Jenkinsfile 中的 NoSuchFileException
- php - 使用文件上传 php 脚本将文件名存储在数据库中并将具有随机名称的文件存储在文件夹中的问题
- javascript - response.pipe(file) 在 Windows Server 上抛出错误 | 在 Ubuntu 上运行良好
- sql-server - 如何解决“数据类型 varchar 和 date 在 add 运算符中不兼容”。问题