게으른 완벽주의자의 개발자 도전기
[Spring Security] 기초 2( 회원가입, 로그인, 로그아웃) 본문
가입하기
controller
가입페이지 이동
@GetMapping("join")
public String joinPage() {
return "join";
}
join.html
<form action="/join" method="post">
아이디 : <input type="text" name="memberId"> <br>
비밀번호 : <input type="password" name="memberPw"> <br>
이름 : <input type="text" name="memberName"> <br>
권한 :
<input type="checkbox" value="MANAGER" name="role"> 매니저
<input type="checkbox" value="ADMIN" name="role"> 관리자
<br>
<input type="submit" value="가입하기">
</form>
mapper
회원가입
<insert id="join">
INSERT INTO SECURITY_MEMBER (
MEMBER_ID
, MEMBER_PW
, MEMBER_NAME
, ROLE
)VALUES(
#{memberId}
, #{memberPw}
, #{memberName}
, #{role}
)
</insert>
serviceImpl
@Override
public void join(MemberVO memberVO) {
sqlsession.insert("memberMapper.join", memberVO);
}
memberVO
@Getter
@Setter
@ToString
public class MemberVO {
private String memberId;
private String memberPw;
private String memberName;
private String role;
public void setRoleAndPw(PasswordEncoder passwordEncoder) {
★memberPw 가져와서 암호화 하겠다.
String pw = passwordEncoder.encode(getMemberPw());
setMemberPw(pw);
권한에 일반회원(member)을 default로 넣겠다.
if(getRole() == null) {
setRole("MEMBER");
}
else {
setRole("MEMBER," + getRole());
}
}
}
controller
가입하기
@PostMapping("/join")
public String join(MemberVO memberVO) {
memberVO.setRoleAndPw(passwordEncoder);
memberService.join(memberVO);
return "login";
}
로그인 페이지로 이동
@GetMapping("/login")
public String login() {
return "login";
}
로그인 실패했을 때 메세지
@GetMapping("/loginFail")
public String loginFail(Model model) {
model.addAttribute("failMsg", "아이디 혹은 비밀번호가 틀렸습니다");
return "login";
}
Security Config.java
미인증 시 내가 만든 로그인 페이지로 이동하도록 설정
security.antMatchers("/login").permitAll()
.formLogin().loginPage("/login");
.defaultSuccessUrl("/index") 로그인 성공하면 index 페이지로
.failureUrl("/loginFail"); 실패하면 실패 메세지 표시
mapper
<mapper namespace="memberMapper">
<resultMap type="kh.study.security.vo.MemberVO" id="member">
<id column="MEMBER_ID" property="memberId"/>
<result column="MEMBER_PW" property="memberPw"/>
<result column="MEMBER_NAME" property="memberName"/>
<result column="ROLE" property="role"/>
</resultMap>
<select id="login" resultMap="member">
SELECT MEMBER_ID
, ROLE
, MEMBER_PW (아이디만 맞으면 다 로그인 될 수 있기 때문에 비밀번호 가져와서 비교)
FROM SECURITY_MEMBER
WHERE MEMBER_ID = #{memberId}
★<!-- AND MEMBER_PW = #{memberPw} -->
★security에서는 비밀번호 조회 허용하지 않음
내부적으로 비밀번호 조회 로직 있음(암호화 되어 있음)
</select>
★security는 기본적으로 아이디, 비밀번호, 권한 3가지를 필수적으로 가져와야 함
비밀번호는 로그인 시도할 때 일치하는지만 판단하고 그 이후로는 알아서 폐기해버린다
그래서 실질적으로 아이디랑 권한만 가지고 있게 된다
serviceimpl
@Override
public MemberVO login(String memberId) {
return sqlsession.selectOne("memberMapper.login", memberId);
}
로그인 실행
로그인 실행 시 controller에 메소드 만들지 않아도
/login이라는 요청을 post 방식으로 보내면 스프링 내부적으로 로그인 처리를 해준다.
<form action="/login" method="post">
ID <input type="text" name="username"><br>
PW <input type="password" name="password"><br>
<div th:text="${failMsg}"></div> 로그인 실패시 메세지
<input type="submit" value="로그인">
★ Security에서는 id에 name은 무조건 username
★ password의 name을 무조건 password로 넣는다
</form>
로그인 실행 메소드 serviceImpl
security에서 로그인 실행 userDetailsService라는 인터페이스 제공한다.
(이를 구현할 클래스 하나 생성해야 함 -> UserDetailsServiceImpl을 우리가 만든다 )
UserDetailsService : 로그인시 실행되는 메소드를 가지고 있는 인터페이스
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService{
@Resource(name="memberService")
private MemberService memberService;
이 메소드가 로그인 시 자동으로 실행된다.
@Override
public UserDetails loadUserByUsername(String username){
MemberVO loginInfo = memberService.login(username);
입력받은 id(input 태그에 name="username"인 것) 매개변수로 받음
if(loginInfo == null) {
System.out.println(username + "이라는 회원은 존재하지 않습니다.");
강제로 예외를 발생시킴
throw new UsernameNotFoundException("오류");
}
UserDetails userDetails = User
.withUsername(loginInfo.getMemberId())
.password(loginInfo.getMemberPw())
.roles(loginInfo.getRole().split(","))
split를 이용하여 "MEMBER, MANAGER, ADMIN" -> "MEMBER", "MANAGER", "ADMIN"
.build();
return userDetails;
}
}
User (org.springframework.security)도 제공한다.
.roles(loginInfo.getRole().split(","))
split를 이용하여 "MEMBER, MANAGER, ADMIN" -> "MEMBER", "MANAGER", "ADMIN"
우리가 회원가입할 때 권한을 선택하도록 체크박스로 해두었다
이때 두가지 모두를 선택하면
String role = "MEMBER, MANAGER, ADMIN" 문자열 자체로 저장되어 버린다.
우리는 각각 권한이 있는 것으로 넣고 싶기 때문에
.split(",")을 이용하여 "MEMBER", "MANAGER", "ADMIN" 각 권한을 구별하고자 함수를 사용함.
customizing한 로그인 페이지로 이동
로그인 실패 화면 예시
DB
1번의 경우 암호화 하지 않았을 때
2, 3번의 경우 암호화 했을 때
로그인한 유저의 정보 추출
@GetMapping("/info")
public String getInfo(Authentication authentication) {
로그인한 유저의 정보를 가져 옴
User user = (User)authentication.getPrincipal();
System.out.println("id=" + user.getUsername());
System.out.println("pw=" + user.getPassword());
권한정보
List<GrantedAuthority>authoList = new ArrayList<>(user.getAuthorities());
for(GrantedAuthority list : authoList) {
System.out.println(list.getAuthority());
}
return"index";
}
비밀번호는 로그인 시 확인 후 폐기해버리기 때문에 null값이 뜨는걸 확인할 수 있다.
로그아웃
<form action="/logout" method="post">
Security를 활용하여 logout을 진행하려면 post방식으로 /logout을 보내주면
controller에 /logout 메소드를 만들지 않아도 실행 된다.
<input type="submit" value="로그아웃">
</form>
'Spring Boot' 카테고리의 다른 글
[Spring Security] 로그인한 사용자 security data 보기 (0) | 2022.09.23 |
---|---|
[Spring Security] 암호화 기능 테스트 (0) | 2022.09.23 |
[Spring Security] 기초 1 (configuration) (0) | 2022.09.22 |
association(1:1관계) (0) | 2022.09.21 |
전화번호(tell) 자바 문자열 치환(replace함수) (0) | 2022.09.21 |