java Spring Security AuthenticationManager设置密码编码器
我使用的是SpringBoot 2.3.1。使用Java14发布
我的Spring Security工作正常,即它可以接收用户名&;密码并返回jwt令牌。针对令牌成功验证了各种api调用
这是我的Web安全配置适配器
SecurityConfig。java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("datasource1")
private DataSource dataSource;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("SELECT username, password, (NOT disabled) as enabled FROM members "+
"WHERE username = ?")
.authoritiesByUsernameQuery("SELECT m.username, t.name as authority FROM members m " +
"JOIN administrator a ON a.member_id = m.member_id " +
"JOIN admin_type t ON t.admin_type_id = a.admin_type_id "+
"WHERE m.username = ?");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// set up the jwt auth
http.cors().disable();
http.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll()//.anyRequest().authenticated()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.and().exceptionHandling()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // don't manage sessions, using jwt
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
// define the role mappings
http.authorizeRequests()
.antMatchers("/admin").hasAuthority("approver admin")
.antMatchers("/approvals").hasAuthority("approver admin")
//.antMatchers("/rest/*").hasAuthority("approver admin")
.antMatchers("/hello").permitAll();
// INSERT INTO admin_type (admin_type_id, name, description) VALUES ((SELECT MAX(admin_type_id) +1 FROM admin_type), 'approver admin', 'Able to alter approval requests');
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new NexctPasswordEncoder();
}
}
我还有一个RESTful资源。这将接收一个包含用户名和原始密码的AuthenticationRequest
批准资源。java
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
);
} catch (BadCredentialsException e) {
logger.info("Incorrect username or password for "+authenticationRequest.getUsername());
throw new Exception("Incorrect username or password", e);
}
final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
final String jwt = jwtTokenUtil.generateToken(userDetails);
final String username = jwtTokenUtil.extractUserName(jwt);
logger.info("User just logged in: "+username);
return ResponseEntity.ok(new AuthenticationResponse(jwt));
}
nextPasswordEncoder。java
public class NexctPasswordEncoder implements PasswordEncoder {
Logger logger = LoggerFactory.getLogger(NexctPasswordEncoder.class);
@Override
public String encode(CharSequence rawPassword) {
return encodeString(rawPassword.toString());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
String encoded = encodeString(rawPassword.toString());
boolean match = encoded.equals(encodedPassword);
return match;
}
private String encodeString(String s) {
String encryptedPassword = null;
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-384");
byte[] pt = s.getBytes();
byte[] out = messageDigest.digest(pt);
encryptedPassword = HexConvert.ByteToHexString(out);
} catch (NoSuchAlgorithmException e) {
logger.error("Error trying to encode password");
}
return encryptedPassword;
}
}
当收到原始(未加密)密码时,这一切都可以完美地与NexctPasswordEncoder
配合使用。NexctPasswordEncoder
加密要与数据库中的加密密码进行比较的密码
问题
我还需要考虑当我收到加密密码而不是原始密码时的情况
解决方案
我需要让上面的内容与两个不同的PasswordEncoder
一起工作
理想情况下,在ApprovalsResource
中,接收带有用户名和密码的请求,并调用以下命令:
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
我想设置相关的PasswordEncoder
(一个加密密码,一个不加密)
问题
如何根据请求中的参数交换PasswordEncoder
# 1 楼答案
实际上,解决方案非常简单强>
您可以执行以下操作之一:
boolean match = encoded.equals(encodedPassword) || rawPassword.equals(encodedPassword);
# 2 楼答案
签出DelegatingPasswordEncoder:https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/password/DelegatingPasswordEncoder.html
它允许根据密码值中的前缀确定要使用的其他密码编码器