[SPRING] 스프링 보안으로 사용자 업데이트시 권한을 다시로드하는 방법
SPRING스프링 보안으로 사용자 업데이트시 권한을 다시로드하는 방법
나는 Spring Security를 사용하는 OpenID에 의한 인증으로 응용 프로그램을 만들고있다. 사용자가 로그인하면 일부 권한이 세션에로드됩니다.
다른 사용자의 권한 (권한 취소, 역할 추가)을 수정할 수있는 권한이있는 사용자가 있습니다. 내 질문은 동적으로 사용자 세션 권한을 변경하는 방법입니다. (다른 사용자 세션을 변경하려고하기 때문에 SecurityContextHolder를 사용할 수 없습니다).
간단한 방법 : 사용자 세션을 무효화하는 방법은 무엇입니까? 더 나은 방법 : 새 권한으로 사용자 세션을 새로 고치지 만 방법은 무엇입니까?
해결법
-
==============================
1.어떤 이유로 든 로그인 한 사용자의 권한을 동적으로 업데이트해야 할 경우 (물론 변경된 경우) 로그 아웃하고 로그인 할 필요없이 Spring SecurityContextHolder의 Authentication 객체 (보안 토큰)를 재설정하면됩니다.
어떤 이유로 든 로그인 한 사용자의 권한을 동적으로 업데이트해야 할 경우 (물론 변경된 경우) 로그 아웃하고 로그인 할 필요없이 Spring SecurityContextHolder의 Authentication 객체 (보안 토큰)를 재설정하면됩니다.
예:
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); List<GrantedAuthority> updatedAuthorities = new ArrayList<>(auth.getAuthorities()); updatedAuthorities.add(...); //add your role here [e.g., new SimpleGrantedAuthority("ROLE_NEW_ROLE")] Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities); SecurityContextHolder.getContext().setAuthentication(newAuth);
-
==============================
2.고마워, 많이 도와 줘! SessionRegistry를 사용하면 getAllPrincipals ()를 사용하여 세션의 현재 활성 사용자와 수정하려는 사용자를 비교할 수 있습니다. 세션이 존재하는 경우, 다음을 사용하여 그의 세션을 무효화 할 수 있습니다 : expireNow () (SessionInformation에서) 재 인증을 강요합니다.
고마워, 많이 도와 줘! SessionRegistry를 사용하면 getAllPrincipals ()를 사용하여 세션의 현재 활성 사용자와 수정하려는 사용자를 비교할 수 있습니다. 세션이 존재하는 경우, 다음을 사용하여 그의 세션을 무효화 할 수 있습니다 : expireNow () (SessionInformation에서) 재 인증을 강요합니다.
하지만 securityContextPersistenceFilter의 유용성을 이해하지 못합니까?
편집하다 :
// user object = User currently updated // invalidate user session List<Object> loggedUsers = sessionRegistry.getAllPrincipals(); for (Object principal : loggedUsers) { if(principal instanceof User) { final User loggedUser = (User) principal; if(user.getUsername().equals(loggedUser.getUsername())) { List<SessionInformation> sessionsInfo = sessionRegistry.getAllSessions(principal, false); if(null != sessionsInfo && sessionsInfo.size() > 0) { for (SessionInformation sessionInformation : sessionsInfo) { LOGGER.info("Exprire now :" + sessionInformation.getSessionId()); sessionInformation.expireNow(); sessionRegistry.removeSessionInformation(sessionInformation.getSessionId()); // User is not forced to re-logging } } } } }
-
==============================
3.요점 - 사용자 SecurityContexts에 액세스 할 수 있어야합니다.
요점 - 사용자 SecurityContexts에 액세스 할 수 있어야합니다.
서블릿 환경에 있고 securityContextPersistenceFilter에서 securityContextRepository로 HttpSession을 사용하는 경우 Spring의 SessionRegistry를 사용하여 수행 할 수 있습니다. 강제로 사용자를 다시 인증하려면 (무의미한 사용 권한 해지보다 좋음) HttpSession을 무효화하십시오. web.xml에 HttpSessionEventPublisher를 추가하는 것을 잊지 마십시오.
<listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener>
스레드 로컬 securityContextRepository를 사용하는 경우 springSecurityFilterChain에 사용자 정의 필터를 추가하여 SecurityContexts 레지스트리를 관리해야합니다. 이를 수행하려면 plain-bean springSecurityFilterChain 구성 (보안 네임 스페이스 단축키 사용 안 함)을 사용해야합니다. 사용자 정의 필터를 사용하는 일반 bean 구성의 경우 인증 및 권한 부여를 완전히 제어 할 수 있습니다.
일부 링크는 문제 (OpenID 없음)를 정확히 풀지는 못하지만 유용 할 수 있습니다.
-
==============================
4.다른 사용자의 권한을 다시 인증하도록 강요하지 않으면 서 다른 사용자의 권한을 갱신하는 방법을 아직 찾고있는 사용자는 인증을 다시로드하는 인터셉터를 추가 할 수 있습니다. 그러면 권한이 항상 갱신됩니다.
다른 사용자의 권한을 다시 인증하도록 강요하지 않으면 서 다른 사용자의 권한을 갱신하는 방법을 아직 찾고있는 사용자는 인증을 다시로드하는 인터셉터를 추가 할 수 있습니다. 그러면 권한이 항상 갱신됩니다.
그러나 여분의 인터셉터로 인해 약간의 성능 영향이 있습니다 (예 : 데이터베이스에서 사용자 역할을 얻는 경우 모든 HTTP 요청에 대해 쿼리됩니다).
@Component public class VerifyAccessInterceptor implements HandlerInterceptor { // ... @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); Set<GrantedAuthority> authorities = new HashSet<>(); if (auth.isAuthenticated()) { authorities.add(new SimpleGrantedAuthority("ROLE_USER")); } User userFromDatabase = getUserFromDatabase(auth.getName()); if (userFromDatabase != null) { // add whatever authorities you want here authorities.add(new SimpleGrantedAuthority("...")); } Authentication newAuth = null; if (auth.getClass() == OAuth2AuthenticationToken.class) { OAuth2User principal = ((OAuth2AuthenticationToken)auth).getPrincipal(); if (principal != null) { newAuth = new OAuth2AuthenticationToken(principal, authorities,(((OAuth2AuthenticationToken)auth).getAuthorizedClientRegistrationId())); } } SecurityContextHolder.getContext().setAuthentication(newAuth); return true; } }
이 특정 구현에서는 OAuth2 (OAuth2AuthenticationToken)를 사용하지만 대신 UsernamePasswordAuthenticationToken을 사용할 수 있습니다.
이제 인터셉터를 구성에 추가하십시오.
@Configuration public class WebConfiguration extends WebMvcConfigurationSupport { @Autowired private VerifyAccessInterceptor verifyAccessInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(verifyAccessInterceptor).addPathPatterns("/**"); } }
나는 이것에 관한 기사도 만들었다.
-
==============================
5.TwiN에서 주어진 대답을 사용하지만 성능 영향을 줄이기 위해 제어 변수 (users_to_update_roles)를 만듭니다.
TwiN에서 주어진 대답을 사용하지만 성능 영향을 줄이기 위해 제어 변수 (users_to_update_roles)를 만듭니다.
@Component public class RoleCheckInterceptor implements HandlerInterceptor { public static ArrayList<String> update_role = new ArrayList<>(); @Autowired private IUser iuser; public static Set<String> users_to_update_roles = new HashSet<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); try { CurrentUser current = (CurrentUser) auth.getPrincipal(); String username = current.getUser().getUsername(); if (users_to_update_roles.contains(username)) { updateRoles(auth, current); users_to_update_roles.remove(username); } } catch (Exception e) { // TODO: handle exception } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } private void updateRoles(Authentication auth, CurrentUser current) { User findOne = iuser.findOne(current.getUser().getUsername()); List<GrantedAuthority> updatedAuthorities = new ArrayList<>(); for (Role role : findOne.getRoles()) { updatedAuthorities.add(new SimpleGrantedAuthority(role.name())); } Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities); SecurityContextHolder.getContext().setAuthentication(newAuth); } }
내 컨트롤러에서 역할을 업데이트 한 사용자를 추가합니다.
public ModelAndView roleSave(@PathVariable long numero_documento, Funcionario funcionario) { ModelAndView modelAndView = new ModelAndView("funcionario/role"); Set<Role> roles = funcionario.getPessoa().getUser().getRoles(); funcionario = funcionarioService.funcionarioNumero_documento(numero_documento); funcionario.getPessoa().getUser().setRoles(roles); iUser.save(funcionario.getPessoa().getUser()); RoleCheckInterceptor.users_to_update_roles.add(funcionario.getPessoa().getUser().getUsername()); modelAndView.addObject("funcionario", funcionario); modelAndView.addObject("sucess", "Permissões modificadas"); return modelAndView; }
from https://stackoverflow.com/questions/9910252/how-to-reload-authorities-on-user-update-with-spring-security by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링에 중복 된 양식 제출 [마감] (0) | 2019.01.08 |
---|---|
[SPRING] 성공적인 등록 후 자동 로그인 (0) | 2019.01.08 |
[SPRING] XML 구성없이 @Configuration을 사용하여 데이터베이스 초기화 (0) | 2019.01.08 |
[SPRING] 스프링에 의해 시작된 임베디드 H2 데이터베이스의 내용보기 (0) | 2019.01.08 |
[SPRING] 함수의 매개 변수로 전달하지 않고 Spring에서 현재 사용자 로케일을 얻는 방법? (0) | 2019.01.08 |