我正在尝试在我的Restful API中实现SpringSecurity,但是遇到一个问题,在使用AuthenticationManager
的{{1}}不会在以下情况下考虑我的用户名进行身份验证,只要密码是正确的,它将进行身份验证...,但我希望它与密码和用户名都匹配。
我正在对用户名和密码进行硬编码,但仍未使用任何数据库。
AuthResource(Controller)
AuthenticationPasswordToken();
SecurityConfigurer
@RestController
public class AuthResource {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private JwtUtil jwtTokenUtil;
@PostMapping("/authenticate")
public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthRequestModel authenticationRequest) throws Exception{
String authUsername = authenticationRequest.getUsername();
String authPwd = authenticationRequest.getPassword();
System.out.println("Username: "+ authUsername + " PWD: " + authPwd);
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authUsername, authPwd)
);
}catch(BadCredentialsException e) {
throw new Exception("Incorrect username or Password", e);
}
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authUsername);
final String jwt = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthResponseModel(jwt));
}
}
MyUserDetailsService
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter{
@Autowired
private MyUserDetailsService myUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll()
.anyRequest().authenticated();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
JwtUtil
@Service
public class MyUserDetailsService implements UserDetailsService{
@Autowired
PasswordEncoder pwdEncoder;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
String user = "testUser";
String encodedPwd = pwdEncoder.encode("testPassword");
return new User(user, encodedPwd, new ArrayList<>());
}
}
因此,在@Service
public class JwtUtil {
//ideally should be in a configuration file and not hardcoded like this
private String SECRET_KEY = "mySecretKey";
//extract the username from the token
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
//extract the token expiration
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
public boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}
public boolean validToken(String token, UserDetails userDetails) {
final String userName = extractUsername(token);
return (userName.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
中,我将我的用户名设置为 testUser ,将我的密码设置为 testPassword 。
但是在下面的示例中可以看到,它没有考虑用户名:
现在,如果我更改密码,则会收到访问被拒绝的其他响应
我仍在学习如何使用SpringSecurity,因此这里可能会遗漏一些东西。
EDIT
似乎当我收到“拒绝访问”响应时,它甚至都不会进入控制器中的MyUserDetailsService
方法。