spring-boot-starter-security dependency를 추가하면 Security가 기본적으로 제공하는 로그인 폼을 사용할 수 있다. 사용자명은 “user”, 암호는 콘솔에 출력된다.
인증(Authentication): 로그인 처리
인가(Authorization): 권한(role) 설정
@Configuration
public class SpringConfig {
@Bean //객체 제공자
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//메소드 체이닝
http.authorizeHttpRequests().mvcMatchers("/","/all/**","/signUp").permitAll() //모든 사용자가 접근 가능한 뷰페이지 설정
.mvcMatchers("/admin/**").hasRole("admin") //관리자만 접근 가능한 뷰페이지 설정
.anyRequest().authenticated(); //어떤 요청이든 인증(로그인)되어야 접근 가능
http.formLogin().loginPage("/login").permitAll()
//모든 사용자에게 로그인 페이지에 접근 허용
//로그인 페이지 주소는 "/login"
.defaultSuccessUrl("/service1");
//로그인 성공하면 service1로 보내기
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true) //세션 파괴
.logoutSuccessUrl("/login"); //로그아웃 성공하면 보낼 페이지:login
http.httpBasic(); //나머지는 http 기본 설정을 따름
}
}
HttpSecurity를 통해 인증과 인가에 대한 설정을 한다.
http.authorizeHttpRequest() -> 반환 타입:AuthorizationManagerRequestMatcherRegistry ->이것을 통해 인증과 인가에 대한 구체적 설정 할 수 있음
mvcMatchers(String ... ):
어떤 요청은 로그인 안해도 되고 어떤 요청은 어떤 롤이어야 하고 그런 패턴들을 써줌
String ...: String 여러개 가능
permitAll(): 아무나 사용 가능
mvcMatchers("/admin/**"): admin이라는 네임스페이스에 있는 모든 요청은
hasRole("admin") : admin이라는 role을 가지고 있어야 요청 가능
anyRequest(): 나머지 서비스들은
authenticated(): 로그인만 하면 됨
메소드 체이닝으로 써줌
환경설정 이것도 있음 (위랑 차이는 모르겠음,…)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http.authorizeHttpRequests()
.requestMatchers("/", "/member/login", "/member/join").permitAll()
.requestMatchers("/admin/**").hasRole("admin")
.anyRequest().authenticated();
http.formLogin().loginPage("/member/login").permitAll()
.defaultSuccessUrl("/board/list/1/all");
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.logoutSuccessUrl("/member/login");
http.httpBasic();
return http.build();
}
}
@Service
@Setter
public class MemberService implements UserDetailsService{
@Autowired
private MemberDAO dao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
MemberVO m=dao.findById(username);
if(m==null) {
throw new UsernameNotFoundException(username);
}
UserDetails user=User.builder()
.username(username)
.password(m.getPwd())
.roles(m.getRole()).build();
return user;
}
}
form에 토큰 삽입
<input type="hidden" name="${_csrf.parameterName }" value="${_csrf.token }">
@Autowired
private PasswordEncoder passwordEncoder;
@GetMapping("/signUp")
public void signUpForm() {
}
@PostMapping("/signUp")
public ModelAndView signUpSubmit(MemberVO m) {
ModelAndView mav=new ModelAndView("redirect:/login");
m.setPwd(passwordEncoder.encode(m.getPwd()));
int re=-1;
re=dao.insert(m);
if (re!=1) {
mav.setViewName("/all/error");
mav.addObject("msg","회원가입 실패");
}
return mav;
}
<input type="hidden" name="${_csrf.parameterName }" value="${_csrf.token }">
get방식의 뷰만 매핑해주면 됨
@GetMapping("/login")
public void login() {
}
post 방식의 처리는 security가 알아서 해줌
@Controller
public class MemberController {
@GetMapping("/service1")
public void service1(HttpSession session) {
//인증된(로그인한) 회원의 정보를 갖고 오기 위해 먼저 시큐리티의 인증객체가 필요하다.
Authentication authentication=
SecurityContextHolder.getContext().getAuthentication();
//이 인증객체를 통해서 인증된(로그인한) User 객체를 받아온다.
User user=(User) authentication.getPrincipal();
//이 인증된 User를 통해서 로그인한 회원의 아이디를 갖고온다.
String id=user.getUsername();
//이 정보를 세션에 상태유지한다.
//만약 id뿐만 아니라 로그인한 회원의 다른 정보도 필요하다면 dao를 통해 회원의 정보를 가져와서 상태유지한다.
session.setAttribute("id", id);
}
}
Controller에서 Model에 상태유지하면 그 다음 페이지에만 유지됨. 계속 유지되게 하려면 session에 상태유지한다.
뷰에서 상태유지된 아이디를 불러올 때: ${id }