我实现了一个自定义的安全功能和一个登录入口点:
@PostMapping("/login")
public ResponseEntity<UserRestResponseModel> userLogin(@RequestBody UserDetailsRequestModel userDetails) {
if(userDetails.getEmail().isEmpty() || userDetails.getPassword().isEmpty()) {
throw new UserServiceException(ErrorMessages.MISSING_REQUIRED_FIELD.getErrorMessage());
}
authenticate(userDetails.getEmail(), userDetails.getPassword());
UserRestResponseModel userRestResponseModel = new UserRestResponseModel();
ModelMapper modelMapper = new CustomMapper();
//modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
UserDto loggedInUser = userService.getUser(userDetails.getEmail());
if (loggedInUser == null)
throw new UserServiceException("Error !!");
if(loggedInUser.getIsAccountNonLocked() == Boolean.FALSE)
throw new UserServiceException("User account is locked");
userRestResponseModel = modelMapper.map(loggedInUser, UserRestResponseModel.class);
UserPrincipal userPrincipal = modelMapper.map(loggedInUser, UserPrincipal.class);
HttpHeaders jwtHeader = getJwtHeader(userPrincipal);
ResponseEntity<UserRestResponseModel> returnValue =
new ResponseEntity<>(userRestResponseModel, jwtHeader, HttpStatus.OK);
return returnValue;
}
private void authenticate(String userName, String password) {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password));
}
private HttpHeaders getJwtHeader(UserPrincipal userPrincipal) {
HttpHeaders headers = new HttpHeaders();
String token = jwtTokenProvider.generateJwtToken(userPrincipal);
headers.add(SecurityConstants.TOKEN_PREFIX, token);
return headers;
}
我还实现了userprincipal类:
public class UserPrincipal implements UserDetails {
private static final long serialVersionUID = 7464059818443209139L;
private UserEntity userEntity;
private String userKeyId;
public UserPrincipal(){ }
public UserPrincipal(UserEntity userEntity) {
this.userEntity = userEntity;
this.userKeyId = userEntity.getUserKeyId();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new HashSet<>();
Collection<AuthorityEntity> authorityEntities = new HashSet<>();
// get user roles
Collection<RoleEntity> roles = userEntity.getRoles();
if (roles == null) {
return authorities; // null
}
// get user roles
roles.forEach((role) ->{
authorities.add(new SimpleGrantedAuthority(role.getName()));
authorityEntities.addAll(role.getAuthorities());
});
// get user authorities
authorityEntities.forEach(authorityEntity ->
authorities.add(
new SimpleGrantedAuthority(authorityEntity.getName())
)
);
return authorities;
}
@Override
public String getPassword() {
return this.userEntity.getEncryptedPassword();
}
@Override
public String getUsername() {
return this.userEntity.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return this.userEntity.getIsAccountNonExpired();
}
我还有一个处理令牌的jwttokenprovider类。
@Component
public class JwtTokenProvider {
public String generateJwtToken(UserPrincipal userPrincipal) {
String[] claims = getClaimsFromUser(userPrincipal);
return JWT.create()
.withIssuer(SecurityConstants.TOKEN_ISSUER)
.withAudience(SecurityConstants.TOKEN_AUDIENCE)
.withIssuedAt(new Date())
.withSubject(userPrincipal.getUsername())
.withArrayClaim(SecurityConstants.AUTHORITIES, claims)
.withExpiresAt(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(SecurityConstants.getTokenSecret().getBytes()));
}
public List<GrantedAuthority> getAuthorities(String token) {
String[] claims = getClaimsFromToken(token);
return stream(claims).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
public Authentication getAuthentication(String userName,
List<GrantedAuthority> authorities,
HttpServletRequest request) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userName, null, authorities);
usernamePasswordAuthenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
return usernamePasswordAuthenticationToken;
}
public boolean isTokenValid(String userName, String token) {
JWTVerifier verifier = getJWTVerifier();
return StringUtils.isNotEmpty(userName) && !isTokenExpired(verifier, token);
}
public String getSubject(String token) {
JWTVerifier jwtVerifier = getJWTVerifier();
return jwtVerifier.verify(token).getSubject();
}
private boolean isTokenExpired(JWTVerifier verifier, String token) {
Date expirationDate = verifier.verify(token).getExpiresAt();
return expirationDate.before(new Date());
}
private String[] getClaimsFromToken(String token) {
JWTVerifier verifier = getJWTVerifier();
return verifier.verify(token).getClaim("Authorities").asArray(String.class);
}
private JWTVerifier getJWTVerifier() {
JWTVerifier verifier;
try {
Algorithm algorithm = Algorithm.HMAC512(SecurityConstants.getTokenSecret());
verifier = JWT.require(algorithm).withIssuer(SecurityConstants.TOKEN_ISSUER).build();
} catch (JWTVerificationException e) {
throw new JWTVerificationException(SecurityConstants.TOKEN_CANNOT_BE_VERIFIED);
}
return verifier;
}
private String[] getClaimsFromUser(UserPrincipal userPrincipal) {
List<String> authorities = new ArrayList<>();
for(GrantedAuthority grantedAuthority: userPrincipal.getAuthorities()) {
authorities.add(grantedAuthority.getAuthority());
}
return authorities.toArray(new String[0]);
}
}
一切正常,但我有2个问题:如果我没有一个无参数构造函数在我的userprincipal类,模型Map器返回一个错误。。。
"message": "An error occurred while processing the request ModelMapper mapping errors: Failed to instantiate instance of destination UserPrincipal. Ensure that UserPrincipal has a non-private no-argument constructor. 1 error".
如果我真的添加了一个无参数构造函数,我会有一个空指针异常(userprincipal为空)和一个很好的500错误。它让我发疯。
我的问题就在我的代码里:
UserDto loggedInUser = userService.getUser(userDetails.getEmail());
...
userRestResponseModel = modelMapper.map(loggedInUser, UserRestResponseModel.class);
UserPrincipal userPrincipal = modelMapper.map(loggedInUser, UserPrincipal.class);
HttpHeaders jwtHeader = getJwtHeader(userPrincipal);
暂无答案!
目前还没有任何答案,快来回答吧!