일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- MySQL
- 검색
- subquery
- foreignkey
- WeNews
- AuthenticationEntryPoint
- EC2
- querydsl
- 참조키
- 테스트메소드
- 추후정리
- ㅔㄴ션
- appspec.yml
- 서브쿼리
- application.yml
- Query
- ubuntu
- 포트
- 커밋메세지수정
- 외부키
- 테스트
- 메소드명
- 컨테이너실행
- 2 > /dev/null
- docker명령어
- 예약
- appspec
- 적용우선순위
- 네이티브쿼리
- 메세지수정
Archives
- Today
- Total
제뉴어리의 모든것
spring security 중복 로그인 방지 본문
WebSecurityConfigurerAdapter 상속 받은 SecurityConfig 클래스의 구현 부분.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.maximumSessions(1) /* session 허용 갯수 */
.expiredUrl("/member/login") /* session 만료시 이동 페이지*/
.maxSessionsPreventsLogin(false); /* 동일한 사용자 로그인시 x, false 일 경우 기존 사용자 session 종료*/
}
HttpSecurity의 여러가지 설정 예. (protected void configure(HttpSecurity http) 부분 참조할것)
package com.example.demo.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.example.demo.entity.com.ComAuthGrpMenuMap;
import com.example.demo.entity.com.ComMenuMngt;
import com.example.demo.security.SecurityAccessDeniedHandler;
import com.example.demo.security.SecurityAuthenticationFailureHandler;
import com.example.demo.security.SecurityAuthenticationProvider;
import com.example.demo.security.SecurityAuthenticationSuccessHandler;
import com.example.demo.security.SecurityLogoutSuccessHandler;
import com.example.demo.security.SecuritySessionExpiredStrategy;
import com.example.demo.security.SecurityUserDetailsService;
import com.example.demo.service.UserService;
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private SecurityAuthenticationSuccessHandler securityAuthenticationSuccessHandler;
@Autowired private SecurityAuthenticationFailureHandler securityAuthenticationFailureHandler;
@Autowired private SecurityLogoutSuccessHandler securityLogoutSuccessHandler;
@Autowired private SecurityAccessDeniedHandler securityAccessDeniedHandler;
@Autowired private SecuritySessionExpiredStrategy securitySessionExpiredStrategy;
@Autowired private SecurityUserDetailsService securityUserDetailsService;
@Autowired private SecurityAuthenticationProvider securityAuthenticationProvider;
@Autowired private UserService userService;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/", "/index.html", "/resources/**", "/caution/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login_form.html").permitAll() // 로그인 페이지
.loginProcessingUrl("/auth") // 로그인 처리 URL
.usernameParameter("loginid").passwordParameter("passwd")
.successHandler(securityAuthenticationSuccessHandler.setDefaultUrl("/dashboard/main.html"))
.failureHandler(securityAuthenticationFailureHandler)
.and();
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/common/logout.html"))// 로그아웃 URL
.logoutSuccessHandler(securityLogoutSuccessHandler.setDefTargetUrl(("/login_form.html")))
.clearAuthentication(true)
.invalidateHttpSession(true).and();
http.exceptionHandling()
.accessDeniedHandler(securityAccessDeniedHandler.setDefaultTargetUrl("/caution/access_denied.html")).and(); // 불량 접근 처리
Collection<Matcher> matchers = getAuthUrlAndRols();
for(Matcher matcher : matchers){
http.authorizeRequests().antMatchers(matcher.url).access(matcher.roles);
}
http.authorizeRequests().anyRequest().authenticated().and();
http.sessionManagement()
.maximumSessions(1) // 같은 아이디로 1명만 로그인 할 수 있음
.maxSessionsPreventsLogin(false) // 신규 로그인 사용자의 로그인이 허용되고, 기존 사용자는 세션아웃 됨
.expiredSessionStrategy(securitySessionExpiredStrategy.setDefaultUrl("/caution/session_out.html"))
.and();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
securityAuthenticationProvider.setSecurityUserDetailsService(securityUserDetailsService);
securityAuthenticationProvider.setPasswordEncoder(passwordEncoder());
auth.authenticationProvider(securityAuthenticationProvider);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance(); // 개발용 패스워드 암호화 모듈(비 암호화)로써 실제 사용시 변경해 주어야 한다...
}
/**
* 권한 URL와 그룹 맵핑
*
* @return
* @author "fishingday"
* @see
*/
private Collection<Matcher> getAuthUrlAndRols(){
Collection <Matcher> matchers = new ArrayList<>();
List<ComMenuMngt> comMenuMngtList = userService.findAllComMenuMngtAndAuthGrpMngt();
for(ComMenuMngt comMenuMgt : comMenuMngtList){
Matcher matcher = new Matcher();
String menuUrl = comMenuMgt.getMenuUrl();
matcher.url = menuUrl.substring(0, menuUrl.lastIndexOf("/")) + "/**";
StringBuilder sb = null;
if(comMenuMgt.getComAuthGrpMenuMaps() == null) continue;
if(comMenuMgt.getComAuthGrpMenuMaps().size() > 1){
for(ComAuthGrpMenuMap comAuthGrpMenuMap : comMenuMgt.getComAuthGrpMenuMaps()){
if(sb == null){
sb = new StringBuilder("hasAnyRole('ROLE_G").append(comAuthGrpMenuMap.getComAuthGrpMngt().getAuthGrpMngtSeq()).append("'");
}else{
sb.append(" ,'ROLE_G").append(comAuthGrpMenuMap.getComAuthGrpMngt().getAuthGrpMngtSeq()).append("'");
}
}
sb.append(")");
}else{
sb = new StringBuilder("hasRole('ROLE_G").append(comMenuMgt.getComAuthGrpMenuMaps().get(0).getComAuthGrpMngt().getAuthGrpMngtSeq()).append("')");
}
matcher.roles = sb.toString();
matchers.add(matcher);
}
return Collections.unmodifiableCollection(matchers);
}
class Matcher {
String url;
String roles;
}
}
두가지를 사용하여 합친 결과물
package org.zerock.member_board.config;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.context.SecurityContextRepository;
import org.zerock.member_board.service.CustomOAuth2UserService;
import org.zerock.member_board.service.MemberService;
import org.zerock.member_board.service.MemberServiceImpl;
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
private final MemberServiceImpl memberService;
private final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/", "/replies/**","/board/list","/board/read","/css/**","/login/**",
"/vendor/**","/modal/**","/member/**","/login/**",
"/review/**","/img/**","/attend/getAttend","/websocket/**",
"/ws_sock/**","/chat/**","/html/**","/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/member/login")
.defaultSuccessUrl("/")
.and()
.logout()
.logoutSuccessUrl("/member/login")
.and()
.oauth2Login().defaultSuccessUrl("/")
.userInfoEndpoint().userService(customOAuth2UserService)
.and();
http.sessionManagement()
.maximumSessions(1)
.expiredUrl("/member/login")
.maxSessionsPreventsLogin(false);
}
public void configure(AuthenticationManagerBuilder auth) throws Exception { // 9
auth.userDetailsService(memberService)
// 해당 서비스(userService)에서는 UserDetailsService를 implements해서
// loadUserByUsername() 구현해야함 (서비스 참고)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
http.sessionManagement() 를 따로 설정함.
출처 : springboot 2.x spring security 중복로그인 방지, logout 시 session 삭제 안될때 처리 :: 2010년 5월 1일, 2막 (novasky.net)
'Spring Boot > Spring Security' 카테고리의 다른 글
Filter 등록시 순서 유의 사항 (0) | 2022.09.27 |
---|---|
Spring Security와 Thymeleaf 기능을 사용하는 HTML 에서 사용시 주의사항 (1) | 2022.09.23 |
Spring Security 적용시 주의사항.. (0) | 2021.04.08 |
[Spring Security] 현재 로그인한 사용자 정보 가져오기 (0) | 2021.02.27 |
html 태그에 sec 속성 넣어서 인증 (Authenticate) 여부에 따라 출력하기 (0) | 2021.02.27 |