OS: Windows 10
IDE: eclipse 2022-03
JAVA: 17
로그인 중인 유저의 정보(권한 등)를 클라이언트 단에서 수정 시 변경된 정보를 Spring Security로 인증해서 HttpSession에도 반영시키자~!
반드시 새로운 Authentication을 생성해서 SecurityContextHolder에 설정해주어야 함.
@Transactional
@RequestMapping("/url")
public Map<String, Object> modify(@RequestBody Map<String, Object> param) {
// 1. 유저 정보 업데이트 쿼리 실행 (소스 생략)
.
.
.
// 2. 현재 Authentication에 저장된 account의 age값 변경
// 2-1. 현재 Authentication 정보 호출
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserAccount userAccount = (UserAccount) authentication.getPrincipal();
// 2-2. 현재 Authentication로 사용자 인증 후 새 Authentication 정보를 SecurityContextHolder에 세팅
SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(authentication,userAccount.getUsername()));
.
.
.
return map;
}
createNewAuthentication(Authentication, userAccount.getUsername())
: 새로운 Authentication
객체를 리턴/**
* @description 새로운 인증 생성
* @param currentAuth 현재 auth 정보
* @param username 현재 사용자 Id
* @return Authentication
* @author Armton
*/
protected Authentication createNewAuthentication(Authentication currentAuth, String username) {
UserDetails newPrincipal = accountService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken newAuth = new UsernamePasswordAuthenticationToken(newPrincipal, currentAuth.getCredentials(), newPrincipal.getAuthorities());
newAuth.setDetails(currentAuth.getDetails());
return newAuth;
}
UsernamePasswordAuthenticationToken
: SecurityContextHolder.getContext()에 등록될 Authentication 객체
newPrincipal
: 현재 로그인 된 사용자의 username
을 이용해 이미 업데이트 된 사용자 조회 및 바인딩newAuth
: 사용자의 ① 새로운 정보(newPrincipal
)와 ② 다시 조회된 사용자 권한(newPrincipal.getAuthorities()
)과 ③ 아직 업데이트 되지 않은 현재 사용자의 자격 증명(currentAuth.getCredentials()
)을 통해 인증된 Authentication
객체를 생성newAuth.setDetails()
: 새 인증 객체에 기존 details
바인딩 @Service
public class AccountService implements UserDetailsService {
@Autowired
AccountDao accountDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountDao.getAccountById("account.getAccountById", username); // DB에서 UserId로 사용자 조회
if (account == null) {
throw new UsernameNotFoundException(username);
}
return new UserAccount(account);
}
AuthenticationManager
객체로 UsernamePasswordAuthenticationToken
객체를 익명으로 생성하여 바로 바인딩 시도.
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(account.getId(), account.getPassword()));
-> 안됨. Failed to authenticate since password does not match stored value
1번에서 생성된 Authentication
객체를 SecurityContextHolder
에 등록
Authentication authentication1 = authenticationManager.authenticate(authentication);
SecurityContextHolder.getContext().setAuthentication(authentication1);
-> 안됨. Failed to authenticate since no credentials provided
덕분에 도움을 받았습니다. 감사합니다