spring-security-web
spring-security-config
spring-security-core
spring-security-taglibs
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.4.6</version>
</dependency>
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml
</param-value>
</context-param>
<!-- security filter -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>코드를 입력하세요
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- <http auto-config="true" 기본 로그인 창 사용시 use-expressions="true"> -->
<http use-expressions="true">
<intercept-url pattern="/cars/add/**" access="hasAuthority('USER_MANAGER')" />
<intercept-url pattern="/**" access="permitAll" />
<form-login login-page="/login"
default-target-url="/cars"
authentication-failure-url="/loginfailed"
username-parameter="username"
password-parameter="password" />
<csrf/>
<logout logout-url = "/logout" logout-success-url = "/login" invalidate-session="true"/>
</http>
<!-- 암호화를 위한 passwordEncoder -->
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<!-- DB연동은 data_source만 지정해주면 된다, 테이블이름은 정확히. users 랑 authorities -->
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"/>
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
post로 요청할때 토큰을 포함시키지 않으면 403에러가 발생한다.
보안 토큰을 안보낼거면 <security:csrf disabled="true"/> 을 통해 비활성화를 해야 post로 요청이 가능하다.
<input type = "hidden" name = "${_csrf.parameterName }" value = "${_csrf.token }">
{noop} // 비밀번호 암호화 안할때 임시로 쓰기
Spring Security에서 Role의 경우에는 prefix로 "ROLE_" 이라는 문자를 자동으로 붙인다.
use-expressions="true” (default값이 true) //false이면 SpEL을 사용하지 않고 일반적인 방법으로 작성
false -> access="ROLE_ANONYMOUS”
true -> access=”hasAuthority('ROLE_ANONYMOUS')”
BCrypt 암호화는 디비의 password를 char(60)로 하는 것이 좋다.
고정된 문자열 크기는 varchar보다 char 타입이 빠르게 작동한다.
CREATE TABLE `users` (
`uno` INT(10) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
`password` CHAR(60) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
`enabled` TINYINT(1) NOT NULL DEFAULT '1',
`uname` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_0900_ai_ci',
`uemail` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_0900_ai_ci',
PRIMARY KEY (`username`) USING BTREE,
INDEX `uno` (`uno`) USING BTREE
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
AUTO_INCREMENT=10
;
CREATE TABLE `authorities` (
`username` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
`authority` VARCHAR(50) NOT NULL DEFAULT 'USER' COLLATE 'utf8mb4_0900_ai_ci',
UNIQUE INDEX `ix_auth_username` (`username`, `authority`) USING BTREE,
CONSTRAINT `FK_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private BCryptPasswordEncoder pwEncoder;
private UserRepository userRepository;
//(쌩성자 주입) 단일 생성자 @Autowired 생략 가능
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public boolean join(User user) {
user.setPassword(pwEncoder.encode(user.getPassword())); //암호화
return (userRepository.insertInfo(user) == 1) && userRepository.insertAuth(user.getUsername()) == 1
? true : false;
}
}
//컨트롤러
@Controller
public class MemberController {
private UserService userService;
//생성자 주입방식(단일 생성자 autowired 생략 가능)
public MemberController(UserService userService) {
this.userService = userService;
}
@GetMapping("/join")
public String joinView() {return "join";}
@PostMapping("/join")
public String join(@ModelAttribute User user) {
if(userService.join(user)) {
return "redirect:/login";
}
return "redirect:/join";
}
@GetMapping("/login")
public String login() {return "login";}
@GetMapping("/loginFailed")
public String logoutFailed() {return "login";}