개인 프로젝트를 만들고 있는데
어제오늘 해서
스프링 시큐리티로 로그인 회원가입
그리고 게시판 작성 리스트까지 완료하고
시큐리티 관련은 포스팅하면서 정리하는 것이 좋지 않을까
하고 작성한 코드를 예제로 설명하겠습니다.
먼저 security-context.xml
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="kr.co.korea.dao"/>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/board/**" access="hasAnyRole('ROLE_MEMBER','ROLE_ADMIN')" />
<intercept-url pattern="/**" access="permitAll" />
<form-login
username-parameter="loginid"
password-parameter="loginpwd"
login-processing-url="/loginok"
login-page="/member/login"
authentication-failure-handler-ref="loginFailHandler"
authentication-success-handler-ref="loginSuccessHandler"
/>
<logout
logout-url="/logout"
logout-success-url="/"
/>
<session-management>
<concurrency-control max-sessions="1"/>
</session-management>
<csrf disabled = "true" />
</http>
<authentication-manager>
<authentication-provider ref="userAuthProvider"/>
<authentication-provider user-service-ref="userService">
</authentication-provider>
</authentication-manager>
<beans:bean id="loginSuccessHandler" class="kr.co.korea.handler.LoginSuccessHandler">
<beans:property name="loginidname" value="loginid" />
<beans:property name="defaultUrl" value="/"/>
</beans:bean>
<beans:bean id="loginFailHandler" class="kr.co.korea.handler.LoginFailHandler">
<beans:property name="loginidname" value="loginid"/>
<beans:property name="loginpwdname" value="loginpwd"/>
<beans:property name="defaultFailurl" value="/member/login?error"/>
</beans:bean>
<beans:bean id="userService" class="kr.co.korea.service.MemberAuthService" />
<beans:bean id="userAuthProvider" class="kr.co.korea.service.MemberProvider"/>
</beans:beans>
먼저 위에서부터 하나씩 설명을 하자면
context:component-scan -> dao 패키지를 scan 하는 것인데 가끔 시큐리티에서 못 읽는 경우가 있다.(경험...)
그래서 root-context에서 설정해뒀지만 한번 더 설정해두는 것.
http | 여기서부터 시큐리티의 기본 적인 내용들이 담김. |
intercept-url |
말 그대로 인터셉터이다. access로 권한을 부여하는데 hasRole(단일 admin만 접속 가능한 페이지) hasAnyRole(복수 권한을 부여한 여러 사람들이 접속 가능) permitAll 모든 사용자 로그인 필요 x |
form-login | 로그인 페이지로 인터셉터한다고 생각하면 편하다. |
username-parameter | username이지만 우리가 알고 있는 id값 (form의 input의 name) |
password-paramete | 비밀번호 값 |
login-processing-url | login 페이지의 form의 action 값 |
authentication-failure-handler-ref | 로그인을 실패했을 시 |
authentication-success-handler-ref | 로그인을 성공했을 시 |
login-page | 로그인하는 페이지 |
이 이외에도 여러 가지가 있는데 현재의 나에게 필요한 것은
이 정도...?라고 생각했다.
logout | logout 할 때 |
logout-url | logout 할 페이지 |
logout-success-url | 로그아웃 성공했을 시(나의 경우에는 메인으로) |
<session-management><concurrency-control max-sessions="1"/></session-management> | 이 부분은 최대 로그인 가능한 수인데 즉, 다른 곳에서 로그인 시도 한 경우 사전에 로그인되어있으면 그것은 로그아웃. |
authentication-manager | 권한을 여기서부터 설정. |
<authentication-provider ref="userAuthProvider"/> | 시큐리티에서 값을 받아오면 그 값을 service로 보내고 해당 값이 일치하고 존재할 경우 그것을 토큰으로 넘기는 역할, 여기서 service로 넘어가기 때문에 위에 뒀다. |
<authentication-provider user-service-ref="userService"/> | 우리가 흔히 아는 Service 단지 UserDetailsService를 상속받아서 사용 |
그리고 아래의 beans:bean은 각 해당하는 부분의
handlere와 service, provider이다.
그다음은 bean부분
public class MemberAuthBean implements UserDetails{
private String mid;
private String mpwd;
private String AUTHORITY;
private boolean ENABLED;//사용여부
private String mname;//이름
private int mlevel;//사용자 권한 레벨
private int mdrop;//사용자 탈퇴 여부
public void setAUTHORITY(String aUTHORITY) {
AUTHORITY = aUTHORITY;
}
public int getMlevel() {
return mlevel;
}
public void setMlevel(int mlevel) {
this.mlevel = mlevel;
}
public int getMdrop() {
return mdrop;
}
public void setMdrop(int mdrop) {
this.mdrop = mdrop;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
ArrayList<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
auth.add(new SimpleGrantedAuthority(AUTHORITY));
return auth;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return mpwd;
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return mid;
}
public String getNAME() {
return mname;
}
public void setNAME(String nAME) {
mname = nAME;
}
public void setENABLED(boolean eNABLED) {
ENABLED = eNABLED;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;//계정 만료 여부
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;//계정 잠김 여부
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;//비밀번호 만료 여부
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return ENABLED;//계정 사용 가능한지 여부
}
오버라이드 부분 이외에는
전부 개인이 정의를 해두면 된다.
나의 경우 권한을 level로 바로 설정해두었고
탈퇴 여부 도 알아야 해서 mdrop으로 설정.
그다음 memberservice
public class MemberAuthService implements UserDetailsService{
@Autowired
private MemberAuthDao memberdao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
MemberAuthBean member = memberdao.getMeminfo(username);
if(member==null) {
throw new UsernameNotFoundException(username);
}
if(member.getMdrop()!=0) {
member.setENABLED(false);
}else {
member.setENABLED(true);
}
if(member.getMlevel()==0) {
member.setAUTHORITY("ROLE_MEMBER");
}else {
member.setAUTHORITY("ROLE_ADMIN");
}
return member;
}
보통은 이렇게 하는가... 싶기도 한데
탈퇴 여부와 권한을 여기서 해결했다.
그리고 마지막 provider부분.
public class MemberProvider implements AuthenticationProvider{
@Autowired
private UserDetailsService userdservice;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// TODO Auto-generated method stub
String username = (String) authentication.getPrincipal();//입력받은 아이디
String password = (String) authentication.getCredentials();//입력받은 비밀번호
MemberAuthBean user = (MemberAuthBean) userdservice.loadUserByUsername(username);
if(!matchPassword(password, user.getPassword())) {
throw new BadCredentialsException(username);
}
if(!user.isEnabled()) {
throw new BadCredentialsException(username);
}
//토큰으로 ㄱ
return new UsernamePasswordAuthenticationToken(username, password, user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
private boolean matchPassword(String loginPwd, String password) {
return loginPwd.equals(password);
}
만약 본인이 session에 id와 비밀번호 이외에도 여러 정보를 넘기고 싶으면
'토큰으로 ㄱ'하는 부분에 username이 아니라
bean을 그대로 넣어주면 된다. 그리고 password를 null로 설정 후
controller단에서 bean을 다시 설정해주면 된다.
처음에 시큐리티 할 때 몇일을 고생하다 보니
어느 정도의 구글링도 필요하지만
흐름이 대충 눈에 보여서
금방 한 것 같다
'spring > 게시판' 카테고리의 다른 글
스프링 게시판 좋아요 버튼 (0) | 2021.04.24 |
---|---|
스프링 Rest CRUD 구현 (0) | 2021.04.07 |
스프링 이미지 업로드 (0) | 2021.03.11 |
스프링 selectKey (0) | 2021.03.02 |
게시판 만들기 (댓글) ajax 정리 (0) | 2021.02.23 |