✅ 회원/관리자별로 다르게 통과시키기
👉 admin 은 /admin/** 하위폴더를 들어갈 수 있고 ADMIN 과 MEMBER는 /member/** 만 들어갈 수 있도록 나눠주었다.
✅ password encoder
👉 로그인을 했는데 password encoder 에러가 났다.
👉 패스워드 인코더는 여러가지 방법을 사용한다.
#️⃣ {noop} 사용하기 --> 추가 인코딩 정없이 패스워드 그대로 패스됨!
@Bean
public UserDetailsService userDetailsService() {
UserDetails user1 = User.builder().username("newlec").password("{noop}111").roles("MEMBER","ADMIN").build(); //noop처리를 해놓은건 password 입력대로 패스된다
UserDetails user2 = User.builder().username("OctaP").password("123").roles("MEMBER").build();
//반환해주면 콩자루에 담아서 스프링이 쓸 예정.
return new InMemoryUserDetailsManager(user1,user2);
//이렇게 객체생성하지말고 builder를 사용해야함
// UserDetails user1 = new UserDetails();
}
#️⃣ 로그인시 상태 변경 (헤더의 아이콘 변경)
- 세션에 저장해둔 사용자 정보를 꺼내와서 사용한다.
- 쿠키는 인증을 하고나면 생기지만 (* 세션키를 받았으니 생김) 쿠키에선 사용자정보를 알 수 없음.
- 우리는 재스퍼한테 지시해서 세션정보를 읽어오라고 해야하는거지, 어디에 키가 있는지 찾아서 직접 꺼낼필요는 없음.
🔥 뷰에서 타임리프를 통해서 스프링 세션정보를 읽어내는 라이브러리 (keyword : maven thymeleaf extras spring security)
* 부트 3에 대응되는 타임리프가 6이므로, maven에서도 security6로 찾아서 연결해준다!
https://github.com/thymeleaf/thymeleaf-extras-springsecurity
GitHub - thymeleaf/thymeleaf-extras-springsecurity: Thymeleaf "extras" integration module for Spring Security 3.x and 4.x
Thymeleaf "extras" integration module for Spring Security 3.x and 4.x - GitHub - thymeleaf/thymeleaf-extras-springsecurity: Thymeleaf "extras" integration module for Spring Secu...
github.com
🔥 security 태그라이브러리 설정을 통해 얻을 수 있는것
- 인증정보를 세션에서 가져온다
- 권한에 관한 내용
👉 인증정보를 출력할수도 있고 비교할수도 있다. (이 두가지만 가능)
<ul class="d:none md:d:flex">
<li><a class="icon icon-cart icon-color:base-0" href="">장바구니</a></li>
<li><a class="icon icon-alert icon-color:base-0 icon-count-with" href="">알림<span>2</span></a></li>
<li><a class="icon icon-person icon-color:base-0" href="/user/login">로그인</a></li>
<li sec:authorize="?" sec:authentication="?"><a class="icon icon-sign-out icon-color:base-0" href="">로그아웃</a></li>
</ul>
- authorize 사용자가 인증이 되었는지, 권한이 있는지 확인하는 용도
- authentication 사용자의 이름이나 롤 정보 등 텍스트를 뽑고싶을때 사용
authenticated로 물어보는경우가 많지 anonymous로 물어보는 경우는 많지 않다
https://docs.spring.io/spring-security/reference/
Spring Security :: Spring Security
If you are ready to start securing an application see the Getting Started sections for servlet and reactive. These sections will walk you through creating your first Spring Security applications. If you want to understand how Spring Security works, you can
docs.spring.io
Expression-Based Access Control :: Spring Security
Any Spring-EL functionality is available within the expression, so you can also access properties on the arguments. For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write
docs.spring.io
👉 6버전 표현식이 어려우면 5버전을 참고해도 됨!
<ul class="d:none md:d:flex">
<li><a class="icon icon-cart icon-color:base-0" href="">장바구니</a></li>
<li><a class="icon icon-alert icon-color:base-0 icon-count-with" href="">알림<span>2</span></a></li>
<li sec:authorize="isAnonymous()"><a class="icon icon-person icon-color:base-0" href="/user/login">로그인</a></li>
<li sec:authorize="isAuthenticated()" ><a class="icon icon-sign-out icon-color:base-0" href="/logout">로그아웃</a></li>
<!--sec:authentication="?"-->
</ul>
👉 member/index로 들어가면 아이콘이 배타적으로 나오며, isAnonymous() 말고 !isAuthenticated()로 사용해도 된다.
👉 로그아웃은 a태그에 /logout을 설정해두면 알아서 처리된다!
✅ 로그아웃 구현
로그아웃은 로직을 호출하면 됨!
#️⃣ 로그아웃 경로 설정하기
그냥 /logout 지시어로 하면 로그인페이지로 돌아가므로, 원하는 페이지로 지정해준다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // 여기선 함수여도 행위명이 아닌 대상으로 이름을 정의함
// 인증을 요구하는 url은 따로있어.로 구분해줌
// 막을때는 어떤 url에 어떤 역할자만 가능한지를 설정하면 된다.
// 이제는 람다식으로 써줘야 함
// 해당 경로 허용 ("/member/*") 하위의 하위디렉토리까지 허가할때는 ("/member/**")
// 나중에 서비스할때는 disable내용 지워주고 각 폼태그 hidden input에다가 스프링이 제공해주는 토큰을 심는 작업을 해주면 됨
http.csrf(csrf->csrf.disable()).authorizeHttpRequests(authorize -> authorize.requestMatchers("/admin/**").hasAnyRole("ADMIN").requestMatchers("/member/**")
.hasAnyRole("ADMIN","MEMBER").anyRequest().permitAll()).formLogin(form -> form.loginPage("/user/login"))
.logout(logout->logout.logoutUrl("/user/logout").logoutSuccessUrl("/index"));
return http.build();
}
👉 이렇게 설정한 이후로는 경로가 맞아야 로그아웃된다
✅ 기본페이지 지정하기 (웰컴파일 리스트 인터셉트)
👉 webMvcConfig -- 인터페이스 webMvcConfigurer를 구현한다
👉 요청을 다른곳으로 리디렉션할때 범용적으로 쓸 수 있는 도구
@Configuration
public class RlandWebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/user/login");
}
}
👉 WebMvcContorller에서 루트의 경로를 /user/login으로 설정함 ▶ 아무 리소스도 요청하지않고 루트로 접근하면 알아서 로그인 화면을 띄워준다.
👉 즉 기본화면을 index로 하고싶으면 "/index"로 하면 됨!
👉 만약 "/member/index"로 세팅해둔다면 security 설정에 의해 로그인화면으로 이동된다.
✅ 사용자정보 DB와 연결하기
#️⃣ 사용자정보 만들기 -- jdbc 이용을 위해 UserDetailsService와 유사한 서비스 객체가 필요하다
역할이 없을땐 멤버냐 아니냐, 로그인 했느냐 아니냐만 검증.-> 이 기준으로 작성해본다
@Configuration
public class RlandSecurityConfig { // 스프링 보안과 관련된 것들을 직접 생성해서 콩자루에 담기 위해 만든 클래스
@Autowired
private DataSource dataSource; //application.dev 설정파일에 있는 DataSource를 통해서 디비랑 연결된다 --> jdbc와도 연결됨
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // 여기선 함수여도 행위명이 아닌 대상으로 이름을 정의함
http.csrf(csrf->csrf.disable()).authorizeHttpRequests(authorize -> authorize
// .requestMatchers("/admin/**").hasAnyRole("ADMIN")
.requestMatchers("/member/**")
// .hasAnyRole("ADMIN","MEMBER") //admin이 있는 경우만 진행
.hasAnyRole("MEMBER")
.anyRequest().permitAll()).formLogin(form -> form.loginPage("/user/login"))
.logout(logout->logout.logoutUrl("/user/logout").logoutSuccessUrl("/index"));
return http.build();
}
//jdbc로 사용자 정보 사용
@Bean
public UserDetailsService jdbcUserDetailsService() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource); // jdbc에게 쿼리문을 dataSource에 담아서 전달
return manager;
}
👉 application.dev의 Spring.dataSource에 데이터베이스 api와 이름, 비밀번호를 설정해놓았는데, 스프링은 이걸 읽어서 모두 객체로 담고 있음. 그러므로 그대로 @Autowired해서 db와 연결해준다.
#️⃣ DB를 읽어올 쿼리문 만들기
결과집합을 가져온다 ▶ 이걸 통해서 스프링이 알고싶은 결과는 데이터베이스 모양과 관계없이 테이블명이 아닌! 결과집합!!! 저 세가지 만 나오면 된다.
1. setUserByUsernameQuery
select user_name, password, ? from member;
enabled가 없음 --> sql에서 속성 추가를 하지않고도 만들어냄!
//속성을 생성하면서 상수로 넣는다
select user_name as username , password, 1 enabled from member where user_name='newlec';
2. setAuthoritiesByUsernameQuery
select user_name as username, 'ROLE_MEMBER' authority from member where user_name='newlec';
👉 자바에서 role을 지정할때는 MEMBER로 넣었지만, SQL문에서는 앞에 꼭 ROLE_가 붙어야 인식되므로 주의!
//jdbc로 사용자 정보 사용
@Bean
public UserDetailsService jdbcUserDetailsService() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource); // jdbc에게 쿼리문을 dataSource에 담아서 전달
// ---> user, password, enabled (true, false)만 맞으면 됨 (테이블이 어떻게 되어있는지는 관심 없음
//user와 role을 가져와야한다
manager.setUsersByUsernameQuery("select user_name as username , password, 1 enabled from member where user_name=?");
//유저이름과 더불어 유저이름으로 된 인증정보를 가져와야 한다
manager.setAuthoritiesByUsernameQuery("select user_name as username, 'ROLE_MEMBER' authority from member where user_name=?");
return manager;
}
#️⃣ Spring password encoder
[Features]-[Authenticaton]-[password]
PasswordEncoder :: Spring Security
docs.spring.io
양방향은 복호화를 통해 원문을 찾아낼 수 있지만 지금 사용하고자 하는건 단방향이다! (비밀번호는 복호화 할 필요가 없음). 단방향은 암호화를 하고나면 원문이 훼손됨. 단, 단방향은 같은 원문이라면 같은 암호문이 나온다. (*일종의 지문을 만들어내는 암호알고리즘)
사용자가 값을 입력해서 전달 > 스프링 시큐리티가 인코딩함 -- 디비와 바로 비교하므로 순수텍스트와 인코딩 된 결과가 안맞아서 로그인이 안됨! 즉 디비에 있는 패스워드는 인코딩시켜서 저장시켜놔야 한다. (인코딩 된 결과값은 서로 같으므로 일치된다!)
'😵 ~23.11.10' 카테고리의 다른 글
1024 | 사용자 비밀번호 암호화(인코딩), 사용자 인증정보 관리 Security Context Holder, role 테이블 생성, UserDetailsService 생성 (0) | 2023.10.24 |
---|---|
1023 | VUE 에서 메서드 바인딩 & 불러온 List 값 바인딩하기 (0) | 2023.10.23 |
1020 | [VUE] v-text 와 v-html, methods 옵션 정의와 바인딩하기 (1) | 2023.10.20 |
1020 | 서블릿필터 사용, 스프링Security 설정, CSRF공격 (0) | 2023.10.20 |
1019 | VUE 개념과 라이브러리, v-text & v-model 바인딩 (2) | 2023.10.19 |