7. 로그인
- 서비스 생성
더보기
package com.example.security;
import java.util.Collection;
import com.example.entity.Member;
import com.example.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class MemberDetailsService implements UserDetailsService{
@Autowired
private MemberRepository mRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Member member = mRepository.findById(username).get();
//String의 권한을 collection<>으로 변환
String[] role = {member.getUserrole()};
Collection<GrantedAuthority> roles = AuthorityUtils.createAuthorityList(role);
//이메일, 암호, 권한 정보를 리턴
//import org.springframework.security.core.userdetails.User;
User user = new User(member.getUserid(), member.getUserpw(), roles);
return user;
}
}
- jwt 추가(토큰 생성 및 유효성 확인)
jwt 추가
더보기
package com.example.jwt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
//토큰발행(만료시간), 토큰의 유효성 검사, 토큰과 관련된 메소드
@Service
public class JwtUtil {
//토큰 생성용 보안키
private final String SECRETKEY = "asdfjk";
//정보 추출용 메소드
private<T> T extractClaim(String token, Function<Claims, T> claimsResolver){
final Claims claims = Jwts.parser().setSigningKey(SECRETKEY).parseClaimsJws(token).getBody();
return claimsResolver.apply(claims);
}
//토큰생성(아이디 정보를 이용한 토큰 생성)
public String generateToken(String username){
// long tokenValidTime = 1000 * 60 * 30; //30분
long tokenValidTime = 1000 * 60 * 60 * 4; //4시간
Map<String, Object> claims = new HashMap<>();
String token =Jwts.builder()
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis())) //현재 시간
.setExpiration(new Date(System.currentTimeMillis() + tokenValidTime)) //만료시간
.signWith(SignatureAlgorithm.HS256, SECRETKEY)
.compact();
return token;
}
//토큰 유효성 확인
// vue에서 오는 토큰에서 꺼낸 아이디 정보와
// 시큐리티 세션에 보관되어 있던 아이디 정보
public Boolean validateToken(String token, String userid){
//토큰에서 아이디 정보 추출
final String username = this.extractUsername(token);
//vue에서 오는 토큰에서 꺼낸 아이디 정보와
//시큐리티 세션에 보관되어 있던 아이디 정보
if(username.equals(userid) && !isTokenExpired(token) ){
return true;
}
return false;
}
//토큰에서 아이디 정보 추출하기
public String extractUsername(String token){
return extractClaim(token, Claims::getSubject);
}
//토큰에서 만료 시간 추출하기
private Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
//토큰의 만료시간이 유효한지 확인
public Boolean isTokenExpired(String token){
//만료시간 가져와서 현재시간보다 이전인지 확인
return this.extractExpiration(token).before(new Date());
}
}
- JwtRequestFillter.java(토큰 확인)
더보기
package com.example.jwt;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.example.security.MemberDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
@Component
public class JwtRequestFilter extends OncePerRequestFilter{
@Autowired
JwtUtil jwtUtil;
@Autowired
MemberDetailsService mService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try{
String token = request.getHeader("token");
String username=null;
if(token != null){
//실제 토큰
username = jwtUtil.extractUsername(token);
}
//username과 시큐리티 세션에 있는 사용자 아이디와 비교
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
//토큰은 전달외었고 로그인이 되어야 되는 것만
if(username != null && auth == null ) {
//시큐리티에 로그인 처리 루틴
UserDetails userDetails = mService.loadUserByUsername(username);
if(jwtUtil.validateToken(token, userDetails.getUsername()) ){
UsernamePasswordAuthenticationToken
upat = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
upat.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request) );
SecurityContextHolder.getContext().setAuthentication(upat);
}
}
//컨트롤러로 넘어가는 시점
filterChain.doFilter(request, response);
}
catch(Exception e){
e.printStackTrace();
response.sendError(578,"토큰오류");
}
}
}
- db 연동(SecurityConfig.java)
package com.example.security;
import com.example.jwt.JwtRequestFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration //환경설정 파일
@EnableWebSecurity //security를 적용
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
MemberDetailsService mService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
//환경 설정에서 객체만들기
//회원가입시 암호 방식을 로그인 시 같은 방식으롤 적용해야 하기 때문에
@Bean
public BCryptPasswordEncoder encode(){
return new BCryptPasswordEncoder();
}
//인증방식은 MemberDetailsService를 사용하고,
//암호화 방식은 위에서 만든 @Bean 객체 방식으로 사용
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(mService).passwordEncoder(encode());
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//권한 설정
http.authorizeRequests()
//관리자 로그인 -> 관리자 페이지는 ROLE=ADMIN 만 접속할 수 있다.
.antMatchers("/admin","/admin/*").hasAuthority("ADMIN")
//회원 로그인
.antMatchers("/member","/member/*").permitAll().and();
//필터 추가하기
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
//session 저장 방법
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//h2 console 사용
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
}
- 로그인(MemberController.java)
@Autowired
JwtUtil jwtUtil;
@Autowired
AuthenticationManager authenticationManager;
//로그인
//127.0.0.1:8080/REST/member/login
@RequestMapping(value = "member/login", method = {RequestMethod.POST},
consumes = MediaType.ALL_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> loginPOST(@RequestBody Member member) {
Map<String,Object> map = new HashMap<String, Object>();
try {
authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(
member.getUserid(), member.getUserpw()));
map.put("result", 1L);
map.put("token", jwtUtil.generateToken(member.getUserid()));
} catch (Exception e) {
e.printStackTrace();
map.put("result", e.hashCode());
}
return map;
}
- 로그인 구현
'프로젝트' 카테고리의 다른 글
9. 팀, 에이전트 등록 (0) | 2021.11.24 |
---|---|
8. 회원 정보 수정 (0) | 2021.11.23 |
6. 회원가입 (0) | 2021.11.18 |
5. db 연동 (0) | 2021.11.18 |
4. 보안 해제 (0) | 2021.11.18 |