Spring Boot+Vue 앞 뒤 분리 항목 로그 인 한 사용 자 를 어떻게 제거 합 니까?
15469 단어 springbootvue로그 인 한 사용 자 를 제거
그러나 완벽 하지 않 은 점 이 있 습 니 다.바로 우리 의 사용 자 는 메모리 에 설 치 된 사용자 입 니 다.우 리 는 사용 자 를 데이터베이스 에 넣 지 않 았 습 니 다.정상 적 인 상황 에서 송 형 이 Spring Security 시리즈 에서 말 한 다른 설정 은 모두Spring Security+Spring Data Jpa 가 강하 게 손 을 잡 으 면 안전 관리 가 더 간단 합 니 다!글 을 참고 하여 데 이 터 를 데이터베이스 에 있 는 데이터 로 전환 하면 된다.
본 고 는 본 시리즈 의 13 편 으로 앞의 글 을 읽 으 면 본 고 를 더욱 잘 이해 하 는 데 도움 이 된다.
본 논문 의 사례 는Spring Security+Spring Data Jpa 의 강력 한 합작 을 바탕 으로 안전 관 리 는 더욱 간단 할 수 밖 에 없습니다!라 는 글 로 구 축 될 것 이기 때문에 중복 되 는 코드 는 쓰 지 않 겠 습 니 다.어린이 들 이 익숙 하지 않 으 면 이 글 을 참고 할 수 있 습 니 다.
1.환경 준비
먼저,우 리 는Spring Security+Spring Data Jpa 가 강하 게 손 을 잡 으 면 안전 관리 가 더 간단 합 니 다!글 의 사례 를 열 었 는데 이 사례 는 Spring Data Jpa 와 결합 하여 사용자 데 이 터 를 데이터베이스 에 저장 했다.
그리고 우 리 는 위의 글 에서 언급 된 로그 인 페이지 를 프로젝트 에 복사 합 니 다(문장 끝 에 전체 사례 를 다운로드 할 수 있 습 니 다).
[외부 체인 이미지 전송 에 실 패 했 습 니 다.원본 사이트 에 도 난 방지 체인 체제 가 있 을 수 있 습 니 다.그림 을 저장 하여 직접 업로드 하 는 것 을 권장 합 니 다(img-7XB0viq6-1588898082940)(http://img.itboyhub.com/2020/...]
그리고 Security Config 에서 로그 인 페이지 를 약간 설정 합 니 다:
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
...
.and()
.sessionManagement()
.maximumSessions(1);
}
여 기 는 모두 일반적인 설정 이 니 더 이상 말 하지 않 겠 습 니 다.맨 뒤에 세 션 수 를 1 로 설정 합 니 다.자,설정 이 완료 되면 프로젝트 를 시작 하고 병렬 다 중 로그 인 테스트 를 시작 합 니 다.
여러 개의 브 라 우 저 를 열 고 각각 다단 계 로그 인 테스트 를 진행 합 니 다.우 리 는 모든 브 라 우 저가 로그 인 에 성공 할 수 있 고 로그 인 에 성공 할 때마다 이미 로그 인 한 사용 자 를 차 버 리 지 않 는 다 는 것 을 놀 라 게 발 견 했 습 니 다!
이거 어떻게 된 거 야?
2.문제 분석
이 문 제 를 알 기 위해 서 는 Spring Security 가 사용자 대상 과 session 을 어떻게 저장 하 는 지 알 아야 합 니 다.
Spring Security 에 서 는 Session Registry Impl 류 를 통 해 세 션 정보 에 대한 통일 적 인 관 리 를 실현 합 니 다.이러한 소스 코드(부분)를 살 펴 보 겠 습 니 다.
public class SessionRegistryImpl implements SessionRegistry,
ApplicationListener<SessionDestroyedEvent> {
/** <principal:Object,SessionIdSet> */
private final ConcurrentMap<Object, Set<String>> principals;
/** <sessionId:Object,SessionInformation> */
private final Map<String, SessionInformation> sessionIds;
public void registerNewSession(String sessionId, Object principal) {
if (getSessionInformation(sessionId) != null) {
removeSessionInformation(sessionId);
}
sessionIds.put(sessionId,
new SessionInformation(principal, sessionId, new Date()));
principals.compute(principal, (key, sessionsUsedByPrincipal) -> {
if (sessionsUsedByPrincipal == null) {
sessionsUsedByPrincipal = new CopyOnWriteArraySet<>();
}
sessionsUsedByPrincipal.add(sessionId);
return sessionsUsedByPrincipal;
});
}
public void removeSessionInformation(String sessionId) {
SessionInformation info = getSessionInformation(sessionId);
if (info == null) {
return;
}
sessionIds.remove(sessionId);
principals.computeIfPresent(info.getPrincipal(), (key, sessionsUsedByPrincipal) -> {
sessionsUsedByPrincipal.remove(sessionId);
if (sessionsUsedByPrincipal.isEmpty()) {
sessionsUsedByPrincipal = null;
}
return sessionsUsedByPrincipal;
});
}
}
이런 종류의 소스 코드 는 비교적 길다.나 는 여기 서 비교적 관건 적 인 부분 을 추출 했다.메모리 기반 사용 자 를 사용 했다 면 Spring Security 의 정 의 를 살 펴 보 겠 습 니 다.
public class User implements UserDetails, CredentialsContainer {
private String password;
private final String username;
private final Set<GrantedAuthority> authorities;
private final boolean accountNonExpired;
private final boolean accountNonLocked;
private final boolean credentialsNonExpired;
private final boolean enabled;
@Override
public boolean equals(Object rhs) {
if (rhs instanceof User) {
return username.equals(((User) rhs).username);
}
return false;
}
@Override
public int hashCode() {
return username.hashCode();
}
}
그 자신 이 실제로 equals 와 hashCode 방법 을 다시 쓴 것 을 볼 수 있다.따라서 메모리 기반 사용 자 를 사용 할 때 문제 가 없 으 며 사용자 정의 사용 자 를 사용 하 는 데 문제 가 있 습 니 다.
문제 의 소 재 를 찾 으 면 문 제 를 해결 하 는 것 이 쉬 워 집 니 다.User 류 의 equals 방법 과 hashCode 방법 을 다시 쓰 면 됩 니 다.
@Entity(name = "t_user")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;
@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.PERSIST)
private List<Role> roles;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(username, user.username);
}
@Override
public int hashCode() {
return Objects.hash(username);
}
...
...
}
설정 이 완료 되면 항목 을 다시 시작 하고 다단 계 로그 인 테스트 를 진행 하면 로그 인 한 사용 자 를 성공 적 으로 차 버 릴 수 있 습 니 다.Jpa 가 아 닌 MyBatis 를 사용 했다 면 로그 인 사용자 의 equals 방법 과 hashCode 방법 만 다시 쓰 면 됩 니 다.
3.마이크로 인사 응용
3.1 존재 하 는 문제점
마이크로 인 사 는 현재 JSON 형식 으로 로그 인 되 어 있 기 때문에 프로젝트 가 session 병발 수 를 제어 하면 추가 적 인 문제 가 발생 할 수 있 습 니 다.
가장 큰 문 제 는 사용자 정의 필터 로 UsernamePassword AuthenticationFilter 를 대체 하여 앞에서 말 한 session 에 대한 설정 을 모두 무효 화 하 는 것 입 니 다.모든 관련 설정 은 새 필터 LoginFilter 에서 설정 해 야 합 니 다.Session Authentication Strategy 를 포함 하여 수 동 으로 설정 해 야 합 니 다.
이 는 업 무량 을 가 져 왔 지만 끝나 면 Spring Security 에 대한 이해 가 한층 더 높 아 질 것 이 라 고 믿 습 니 다.
3.2 구체 적 인 응용
구체 적 으로 어떻게 실현 되 는 지 살 펴 보 겠 습 니 다.저 는 주로 관건 적 인 코드 를 열거 합 니 다.전체 코드 는 GitHub 에서 다운로드 할 수 있 습 니 다.https://github.com/lenve/vhr
먼저 첫 번 째 단 계 는 Hr 류 의 equals 와 hashCode 방법 을 다시 씁 니 다.다음 과 같 습 니 다.
public class Hr implements UserDetails {
...
...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Hr hr = (Hr) o;
return Objects.equals(username, hr.username);
}
@Override
public int hashCode() {
return Objects.hash(username);
}
...
...
}
다음은 Security Config 에서 설정 합 니 다.여기 서 저 희 는 Session AuthenticationStrategy 를 제공 해 야 합 니 다.앞에서 session 을 처리 하 는 것 은 Concurrent Session Control AuthenticationStrategy 입 니 다.즉,저 희 는 Concurrent Session Control AuthenticationStrategy 의 인 스 턴 스 를 제공 한 다음 에 Login Filter 에 배치 해 야 합 니 다.그러나 Concurrent Session Control Authentication Strategy 인 스 턴 스 를 만 드 는 과정 에서 Session Registry Impl 대상 이 필요 합 니 다.
앞에서 말 했 듯 이 Session Registry Impl 대상 은 세 션 정 보 를 유지 하 는 데 사 용 됩 니 다.현재 이 물건 도 저희 가 직접 제공 해 야 합 니 다.Session Registry Impl 인 스 턴 스 는 잘 만 들 어 졌 습 니 다.다음 과 같 습 니 다.
@Bean
SessionRegistryImpl sessionRegistry() {
return new SessionRegistryImpl();
}
그리고 Login Filter 에 Session Authentication Strategy 를 설정 합 니 다.다음 과 같 습 니 다.
@Bean
LoginFilter loginFilter() throws Exception {
LoginFilter loginFilter = new LoginFilter();
loginFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
//
}
);
loginFilter.setAuthenticationFailureHandler((request, response, exception) -> {
//
}
);
loginFilter.setAuthenticationManager(authenticationManagerBean());
loginFilter.setFilterProcessesUrl("/doLogin");
ConcurrentSessionControlAuthenticationStrategy sessionStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
sessionStrategy.setMaximumSessions(1);
loginFilter.setSessionAuthenticationStrategy(sessionStrategy);
return loginFilter;
}
저 희 는 여기 서 Concurrent Session Control AuthenticationStrategy 인 스 턴 스 를 수 동 으로 구축 하고 구축 할 때 Session Registry Impl 인 자 를 전달 한 다음 에 session 의 병발 수 를 1 로 설정 한 다음 에 session Strategy 를 Login Filter 에 설정 합 니 다.사실상편에서 우리 의 배치 방안 도 결국 위 와 같이 지금 우리 스스로 이것 을 썼 을 뿐이다.
이것 괜찮아요?없다session 처리 에 또 하나의 관건 적 인 필 터 는 Concurrent Session Filter 라 고 합 니 다.원래 이 필 터 는 우리 가 관리 할 필요 가 없 었 지만 이 필터 에 도 Session Registry Impl 이 사용 되 었 습 니 다.Session Registry Impl 은 현재 우리 가 정의 하고 있 기 때문에 이 필 터 는 우리 도 다시 설정 해 야 합 니 다.다음 과 같 습 니 다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry(), event -> {
HttpServletResponse resp = event.getResponse();
resp.setContentType("application/json;charset=utf-8");
resp.setStatus(401);
PrintWriter out = resp.getWriter();
out.write(new ObjectMapper().writeValueAsString(RespBean.error(" , !")));
out.flush();
out.close();
}), ConcurrentSessionFilter.class);
http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
}
시스템 의 기본 값 대신 Concurrent Session Filter 의 인 스 턴 스 를 다시 만 들 면 됩 니 다.새 Concurrent Session Filter 인 스 턴 스 를 만 들 때 두 개의 인자 가 필요 합 니 다.
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
SessionRegistry sessionRegistry;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
setDetails(request, authRequest);
Hr principal = new Hr();
principal.setUsername(username);
sessionRegistry.registerNewSession(request.getSession(true).getId(), principal);
return this.getAuthenticationManager().authenticate(authRequest);
}
...
...
}
}
여기 서 session Registry.registerNewSession 방법 을 수 동 으로 호출 하여 Session Registry Impl 에 session 기록 을 추가 합 니 다.OK,그 후에 우리 의 프로젝트 설정 이 완성 되 었 습 니 다.
다음 에 vhr 프로젝트 를 다시 시작 하고 다단 계 로그 인 테스트 를 실시 합 니 다.만약 에 자신 이 오프라인 상태 에 빠 지면 다음 과 같은 힌트 를 볼 수 있 습 니 다.
완전한 코드,나 는 이미 vhr 에 업데이트 되 었 으 니,여러분 은 다운로드 하여 공부 할 수 있 습 니 다.
4.소결
자,본 고 는 주로 어린이 들 과 Spring Security 에서 session 병발 문 제 를 처리 할 때 발생 할 수 있 는 구덩이 와 앞 뒤 가 분 리 된 상황 에서 session 병발 문 제 를 어떻게 처리 하 는 지 소개 했다.친구 들 이 GET 가 도 착 했 는 지 모 르 겠 어 요.
본 논문 의 두 번 째 소절 의 사례 는 GitHub 에서 다운로드 할 수 있 습 니 다.https://github.com/lenve/spring-security-samples
수확 이 있 으 면 골 라 서 송 이 형 을 격려 하 세 요~
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.