user :
해시화
권한설정
http
.antMatcher("/users/**")
.authorizeRequests()
.antMatchers("/users/login", "/users/join").permitAll()
.antMatchers("users/mypage").hasRole("USER")
.antMatchers("/users/admin").access("hasRole('ADMIN')")
.antMatchers("/users/admin/del").access("hasRole('ADMIN') or hasRole('SYS')")
.anyRequest().authenticated();
user 로 접속 ▶ user만 접속가능
manager 로 접속 ▶ user, manager 가능
admin 로 접속 ▶ user, manager, admin가능.antMatchers("/user/**").authenticated() // /user/** 은 인증 필요 --> 인증만 되면 들어갈수 있음 .antMatchers("/manager/**").access("hasRole('ROLE_MANAGER') or hasRole('ADMIN')") .antMatchers("/admin/**").hasRole("ADMIN")
package com.oracle.oBootSecurity02.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration // IoC 빈(bean)을 등록
@EnableWebSecurity // 필터 체인 관리 시작 어노테이션
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) // 특정 주소 접근시 권한 및 인증을 위한 어노테이션 활성화
public class SecurityConfig {
@Bean
public BCryptPasswordEncoder encodePwd() {
return new BCryptPasswordEncoder();
}
// 스프링 버전이 올라가면서 WebSecurityConfigurerAdapter 에도 deprecate
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/user/**").authenticated() // /user/** 은 인증 필요 --> 인증만 되면 들어갈수 있음
.antMatchers("/manager/**").access("hasRole('ROLE_MANAGER') or hasRole('ADMIN')")
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/loginForm")
.loginProcessingUrl("/login")
.failureUrl("/loginFail")
.defaultSuccessUrl("/")
;
return http.build();
}
}
count 만들기
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>count 인증성공</h1>
</body>
</html>
<p class="lead">COUNT 권한</p>
<p>
<a class="btn btn-lg btn-info" href="/count">count</a>
<a class="btn btn-lg btn-info" href="/count/2">count2</a>
</p>
@PreAuthorize는 해당 메서드가 호출되기 이전에 검사한다.
실제로 해당 메서드를 호출할 권한이 있는지를 확인한다.
(PostAuthorize는 메서드 호출 이후)
관리자 권한(ROLE_ADMIN)이 없는데 본인 id(username)이 아닌 남의 id를 입력하면 관리자 권한이 없다는 예외처리를 해줬었는데 @PreAuthorize로 간단히 처리할 수 있게 되었다.
@Secured("ROLE_MANAGER")
@GetMapping("/count")
public String count() {
System.out.println("SecurityController02 count Start==========");
return "admin";
}
// @PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ADMIN')")
@PreAuthorize("hasAnyRole('ROLE_MANAGER', 'ROLE_ADMIN')")
// @PostAuthorize //실행 후에 인증. 잘 안쓴다
@GetMapping("/count/2")
public String count2() {
System.out.println("SecurityController02 count Start===========");
return "count";
}
⭐⭐⭐
@RestController
을 사용하여 Rest API를 개발한다.
Controller + ResponseBody
사용목적 --> Ajax + RestApi
🔵 패키지생성 ➡ oBootJpa01
Type :Gradle, java Version : 11, Packaging : Jar
reopository 는 인터페이스 만들기 필수!
service에선 선택
Rest API를 사용하면 json으로 돌려준다.
▶ json으로 돌려주려면 EAGER 를 써야한다.
(@ManyToOne(fetch = FetchType.LAZY)
하면 오류)
Json : {key: value}
key ➡ id / value ➡ 1
key ➡ name / value ➡ 대조영
이때, Postman을 통해 실행
API 개발을 보다 빠르고 쉽게 구현 할 수 있도록 도와주며, 개발된 API를 테스트하여 문서화 또는 공유 할 수 있도록 도와 주는 플랫폼이다.
▶ URL을 통해서 테스트를 하는것은 한계가 있어 Postman
을 사용한다.
<T>
를 사용해 totCount를 보여준다.❓😬 T는 인스턴스를 생성할때 구체적인 타입으로 -> 유연성💡ver22:
stream
을 쓰고.map
을 쓰면 향상형 for문으로 계속 돌아간다.
.map(m->new MemberRtnDto(m.getName(), m.getSal()))
람다식.
List<Member> findMembers
▶▶ List<MemberRtnDto> resultList
package com.oracle.oBootJpaAPI01.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.oracle.oBootJpaAPI01.domain.Member;
import com.oracle.oBootJpaAPI01.service.MemberService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//Controller + ResponseBody
//사용목적 --> Ajax + RestApi
@RestController
@RequiredArgsConstructor
@Slf4j
public class JpaRestApiController {
private final MemberService memberService;
//Bad API
@GetMapping("/restApi/vl/members")
public List<Member> membersVer1(){
log.info("JpaRestApiController membersVer1 START ====");
List<Member> listMember = memberService.getListAllMember();
return listMember;
}
//Good API
//목표 : 이름 & 급여만 전송
@GetMapping("/restApi/v21/members")
public Result membersVer21() { // API를 위한 내장객체를 만든다. (inner class)
List<Member> findMembers = memberService.getListAllMember();
List<MemberRtnDto> resultList = new ArrayList<MemberRtnDto>();
for(Member member : findMembers) {
MemberRtnDto memberRtnDto = new MemberRtnDto(member.getName(), member.getSal());
log.info("restApi/vl/members memberRtnDto.getName() --->" + memberRtnDto.getName());
log.info("restApi/vl/members memberRtnDto.getSal() --->" + memberRtnDto.getSal());
resultList.add(memberRtnDto);
}
log.info("restApi/vl/members resultList.size() --->" + resultList.size());
return new Result(resultList.size(), resultList);
}
//Good API - 람다 버전 (실무에서 많이사용)
//목표 : 이름 & 급여만 전송
@GetMapping("/restApi/v22/members")
public Result membersVer22() { // API를 위한 내장객체를 만든다. (inner class)
List<Member> findMembers = memberService.getListAllMember();
log.info("restApi/v22/members findMembers.size() --->" + findMembers.size());
// 자바 8에서 추가한 스트림(Streams)은 람다를 활용할 수 있는 기술 중 하나
List<MemberRtnDto> memberCollect = findMembers.stream()
.map(m->new MemberRtnDto(m.getName(), m.getSal()))
.collect(Collectors.toList());
log.info("restApi/v22/members memberCollect.size() --->" + memberCollect.size());
return new Result(memberCollect.size(), memberCollect);
}
// T는 인스턴스를 생성할 때 구체적인 타입으로 변경
@Data
@AllArgsConstructor
class Result<T> { //<T>를 쓰면 어떤 객체든 받을 수 있다.
private final int totCout;
private T data;
}
@Data
@AllArgsConstructor
class MemberRtnDto { //<T>를 쓰면 어떤 객체든 받을 수 있다.
private String name;
private Long sal;
}
}