버전 업 참조 :
★★★ 스프링부트 시큐리티 세션정보 변경 , Spring Security는 사용자 세션을 업데이트하는 방법
권한을 업데이트하려면 두 곳에서 인증 오브젝트를 수정.
하나는 보안 컨텍스트에 있고 다른 하나는 요청 컨텍스트.
주요 객체는 org.springframework.security.core.userdetails.User이거나 해당 클래스를 확장.
(UserDetailsService를 재정의 한 경우). 이것은 현재 사용자를 수정하는 데 사용
.
로그인 한 사용자에 대해 스프링 세션을 사용하여 세션을 업데이트하려면 사용자 정의 필터가 필요합니다. 필터는 일부 프로세스에 의해 수정 된 세션 세트를 저장합니다. 메시징 시스템은 새 세션을 수정해야 할 때 해당 값을 업데이트.
요청에 일치하는 세션 키가있는 경우 필터는 데이터베이스에서 사용자를 조회하여 업데이트를 가져옵니다. 그런 다음 세션의 "SPRING_SECURITY_CONTEXT"속성을 업데이트하고 SecurityContextHolder의 인증을 업데이트.
사용자는 로그 아웃 할 필요가 없음
Authentication newAuth = new UsernamePasswordAuthenticationToken({YourPrincipalObject},null,List)
SecurityContextHolder.getContext().setAuthentication(newAuth);
RequestContextHolder.currentRequestAttributes().setAttribute("SPRING_SECURITY_CONTEXT", newAuth, RequestAttributes.SCOPE_GLOBAL_SESSION);
@Component
@Order(UpdateAuthFilter.ORDER_AFTER_SPRING_SESSION)
public class UpdateAuthFilter extends OncePerRequestFilter
{
public static final int ORDER_AFTER_SPRING_SESSION = -2147483597;
private Logger log = LoggerFactory.getLogger(this.getClass());
private Set permissionsToUpdate = new HashSet<>();
@Autowired
private UserJPARepository userJPARepository;
private void modifySessionSet(String sessionKey, boolean add)
{
if (add) {
permissionsToUpdate.add(sessionKey);
} else {
permissionsToUpdate.remove(sessionKey);
}
}
public void addUserSessionsToSet(UpdateUserSessionMessage updateUserSessionMessage)
{
log.info("UPDATE_USER_SESSION - {} - received", updateUserSessionMessage.getUuid().toString());
updateUserSessionMessage.getSessionKeys().forEach(sessionKey -> modifySessionSet(sessionKey, true));
//clear keys for sessions not in redis
log.info("UPDATE_USER_SESSION - {} - success", updateUserSessionMessage.getUuid().toString());
}
@Override
public void destroy()
{
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException
{
HttpSession session = httpServletRequest.getSession();
if (session != null)
{
String sessionId = session.getId();
if (permissionsToUpdate.contains(sessionId))
{
try
{
SecurityContextImpl securityContextImpl = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT");
if (securityContextImpl != null)
{
Authentication auth = securityContextImpl.getAuthentication();
Optional user = auth != null
? userJPARepository.findByUsername(auth.getName())
: Optional.empty();
if (user.isPresent())
{
user.get().getAccessControls().forEach(ac -> ac.setUsers(null));
MyCustomUser myCustomUser = new MyCustomUser (user.get().getUsername(),
user.get().getPassword(),
user.get().getAccessControls(),
user.get().getOrganization().getId());
final Authentication newAuth = new UsernamePasswordAuthenticationToken(myCustomUser ,
null,
user.get().getAccessControls());
SecurityContextHolder.getContext().setAuthentication(newAuth);
session.setAttribute("SPRING_SECURITY_CONTEXT", newAuth);
}
else
{
//invalidate the session if the user could not be found
session.invalidate();
}
}
else
{
//invalidate the session if the user could not be found
session.invalidate();
}
}
finally
{
modifySessionSet(sessionId, false);
}
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
예)
1
/** 스프링 시큐리티 세션 변경 처리 */
//세션 초기화
SecurityContextHolder.clearContext();
UserDetails updateUserDetails = new PrincipalDetails(memberDto);
Authentication newAuthentication = new UsernamePasswordAuthenticationToken(updateUserDetails, null, updateUserDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(newAuthentication);
session.setAttribute("SPRING_SECURITY_CONTEXT", newAuthentication);
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import kr.iei.hotel.member.dto.MemberDto;
// '/login'호출시 여기서 진행
// 로그인 완료시 시큐리티 세션 생성(Security ContextHolder)
// Authentication 타입 객체(세션에 저장될 오브젝트) -> Member정보
@SuppressWarnings("serial") // 원래 SerialVersionUID를 선언해서 warnings를 없애야 함
public class PrincipalDetails implements UserDetails, OAuth2User {
private MemberDto memberDto;
private Map attributes;
// 일반 로그인
public PrincipalDetails(MemberDto memberDto) {
this.memberDto = memberDto;
}
public MemberDto getMemberDto() {
return memberDto;
}
// OAuth 로그인
public PrincipalDetails(MemberDto memberDto, Map attributes) {
this.memberDto = memberDto;
this.attributes = attributes;
}
// 권한 (원래 권한이 여러개 있을 수 있으므로 Collection 루프 돌려야 함)
@Override
public Collection getAuthorities() {
Collection authorities = new ArrayList<>();
// collect.add(new GrantedAuthority() {
// @Override
// public String getAuthority() {
// return memberDto.getMemberRole(); // "ROLE_" + @가 되어야 함
// }
// });
authorities.add( () -> { return memberDto.getMemberRole();});
return authorities;
}
// 권한 (String)
public String getRole() {
return memberDto.getMemberRole();
}
// 일련번호
public Long getNumber() {
return memberDto.getMemberNumber();
}
// 아이디
@Override
public String getUsername() {
return memberDto.getMemberId();
}
// 이름
@Override
public String getName() {
return memberDto.getMemberName();
}
// 닉네임
public String getNick() {
return memberDto.getMemberNick();
}
// 비밀번호
@Override
public String getPassword() {
return memberDto.getMemberPassword();
}
// 이메일
public String getEmail() {
return memberDto.getMemberEmail();
}
// 등급
public String getGrade() {
return memberDto.getMemberGrade();
}
// 전화번호
public String getPhone() {
return memberDto.getMemberPhone();
}
// 변경 권장 기간 내 비밀번호 변경 여부
public boolean getIsPwChanged() {
boolean result = true;
if (memberDto.getMemberPwChangeDate() != null) {
Date pwChangeDate = memberDto.getMemberPwChangeDate();
Calendar baseDate = Calendar.getInstance();
baseDate.setTime(new Date());
baseDate.add(Calendar.DATE, -90);
result = pwChangeDate.after(baseDate.getTime());
}
return result; // true : 변경 불필요, false : 변경 필요
}
// 계정 만료(false) 여부
@Override
public boolean isAccountNonExpired() {
return true;
}
// 계정 정지(false) 여부
@Override
public boolean isAccountNonLocked() {
return true;
}
// 계정 신용(false) 여부
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 계정 활성(false) 여부 (예 : 최종 로그인 후 일정기간 경과 여부 -> 휴면계정)
@Override
public boolean isEnabled() {
return true;
}
@Override
public Map getAttributes() {
return attributes;
}
}

















댓글 ( 4)
댓글 남기기