버전 업 참조 :
★★★ 스프링부트 시큐리티 세션정보 변경 , 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)
댓글 남기기