스프링 시큐리티
스프링 보안을 사용하면 SpEL(Spring Expression Language)을 사용해 강력한 접근 제어 규칙을 만들수 있다.
스프링 보안에서 지원하는 표현식
표현식 |
설명 |
hasRole('role') or hasAuthority('authority') |
현재 사용자가 권한이 있을 경우 true를 반환 |
hasAnyRole('role1','role2') / hasAnyAuthority('auth1','auth2') |
현재 사용자가 최소 하나라도 권한이 있을 경우 true를 반환 |
hasIpAddress("ip-address") |
현재 사용자가 IP 주소를 갖고 있을 경우 true를 반환 |
principal |
현재 사용자 |
Authentication |
스프링 보안 인증 객체에 접근 |
permitAll |
항상 true를 반환 |
denyAll |
항상 false를 반환 |
isAnonymous() |
현재 사용자가 익명일 경우 true를 반환 |
isRememberMe() |
현재 사용자가 Remeber-Me 기능으로 로그인 한 경우 true를 반환 |
isAuthenticated() |
익명 사용자가 아닐 경우 true를 반환 |
isFullyAuthenticated() |
사용자가 익명이 아니고 Remember-Me 사용자도 아닌 경우 true를 반환 |
메소드 보호
package com.example.demo.library.service;
import com.example.demo.library.Book;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class InMemoryBookService implements BookService {
private final Map<String, Book> books = new ConcurrentHashMap<>();
@Override
@PreAuthorize("isAuthenticated()")
public Iterable<Book> findAll() {
return books.values();
}
@Override
@PreAuthorize("hasAuthority('ROLE_USER')")
public Book create(Book book) {
books.put(book.getIsbn(), book);
return book;
}
@Override
@PreAuthorize("hasRole('ROLE_ADMIN') or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
public void remove(String isbn) {
books.remove(isbn);
}
@Override
@PreAuthorize("isAuthenticated()")
public Optional<Book> find(String isbn) {
return Optional.ofNullable(books.get((isbn)));
}
}
package com.example.demo.library.Security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 메소드보호 호출
public class LibrarySecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
@Autowired
private DataSource dataSource;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login.html").setViewName("login"); // 매핑
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and().authorizeRequests()
.antMatchers(HttpMethod.GET, "/books").hasAnyRole("USER", "GUEST")
.antMatchers(HttpMethod.POST, "/books*").hasRole("USER")
.antMatchers(HttpMethod.DELETE, "/books*")
.access("hasRole('ROLE_ADMIN') or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
.mvcMatchers("/","/h2-console/**" ).permitAll().anyRequest().authenticated()
.and().headers().frameOptions().sameOrigin()
.and().csrf().ignoringAntMatchers("/h2-console/**")
.and().logout().logoutSuccessUrl("/")
.and().formLogin().loginPage("/login.html").defaultSuccessUrl("/books.html").failureUrl("/login.html?error=true").permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.rolePrefix("ROLE_")
.usersByUsernameQuery("SELECT USERNAME, replace(PASSWORD, '$2y', '$2a') AS PASSWORD, 'TRUE' as enabled FROM USERS WHERE USERNAME = ?")
.authoritiesByUsernameQuery("SELECT A.USERNAME AS USERNAME, B.AUTHORITY AS AUTHORITIES " +
"FROM USERS as A INNER JOIN AUTHORITIES as B " +
"ON A.USERNAME = B.USERNAME " +
"WHERE A.USERNAME = ?");
}
}
<table>
<thead>
<tr>
<th>제목</th>
<th>작가</th>
<th>ISBN</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<tr th:each="book : ${books}">
<td th:text="${book.title}">제목</td>
<td th:text="${book.authors}">작가</td>
<td>
<a th:href="@{/book.html(isbn=${book.isbn})}" href="#" th:text="${book.isbn}"></a>
</td>
<td>
<a th:href="@{/book/delete(isbn=${book.isbn})}" href="#">삭제</a>
</td>
</tr>
</tbody>
</table>
초기 부팅시 데이터 입력
@PreAuthorize 으로인해 데이터 넣기전 사전작업 해야된다.
출처 : https://stackoverflow.com/questions/58755986/when-adding-preauthorize-to-a-service-class-an-authentication-object-was-not
@Bean
public ApplicationRunner bookInitialLizer(BookService bookService){
return args ->{
Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
Authentication authentication = new UsernamePasswordAuthenticationToken(this.getClass().getName(), "ROLE_USER", authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
bookService.create(new Book("9780061120084", "To Kill a Mockingbird", Collections.singletonList("Harper Lee")));
bookService.create(new Book("9780451524935", "1984", Collections.singletonList("Georeg Orwell")));
bookService.create(new Book("9780618260300", "The Hobbit", Collections.singletonList("J.R.R, Tolkien")));
};
}
'WEB > 스프링 부트 2' 카테고리의 다른 글
MySQL 연결 / 스프링 schema.sql, data.sql / Flyway (0) | 2020.02.13 |
---|---|
내장데이터베이스 Derby (0) | 2020.02.13 |
Spring Security + H2 (0) | 2020.02.12 |
TestRestTemplate, WebTestClient (0) | 2020.02.11 |
Spring Security (0) | 2020.02.10 |