
BoardWrite.jsx(React)
export function BoardWrite() {
const account = useContext(LoginContext);
~~
return (
~~
</Box>
<Box>
<FormControl>
<FormLabel>์์ฑ์</FormLabel>
<Input readOnly value={account.nickName} />
</FormControl>
</Box>
~~
);
}
LoginProvider์์ ๋๋ค์์ ๋ฐ์์ต๋๋ค.LoginProvider์์ ๋๋ค์์ ๋ฐ์์ค๋ ๊ณผ์ ์ login์ ํ์ ๋ setNickName์ผ๋ก nickName์ ์
๋ฐ์ดํธ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋๋ค์์ ๋ฐ์ ์ ์์ต๋๋ค.DB์๋ ๊ฒ์ํ ์์ฑ์๋ฅผ member์ id๋ก ๋ฐ๊ฟ์ค์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ฐ๊ฟ์ฃผ๋ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
BoardController.java
@PostMapping("add")
@PreAuthorize("isAuthenticated()")
public ResponseEntity add(
Authentication authentication,
@RequestBody Board board) {
if (service.validate(board)) {
service.add(board, authentication);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}
@PostMapping("signup")
@PreAuthorize("isAuthenticated()")
public ResponseEntity signup(Authentication authentication, @RequestBody Member member) {
if (service.validate(member)) {
service.add(member);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}
@PreAuthorize("isAuthenticated()")์ ์ฌ์ฉํ์ฌ ํ์ฌ ์ฌ์ฉ์๊ฐ ์ธ์ฆ๋์๋์ง ํ์ธํฉ๋๋ค. ํ์ธํ๋ ๋ฐฉ๋ฒ์ ํ ํฐ์ผ๋ก ํ์ธํฉ๋๋ค.BoardService.java
public void add(Board board, Authentication authentication) {
board.setMemberId(Integer.valueOf(authentication.getName()));
mapper.insert(board);
}
Authentication์ ์ถ๊ฐํ์ฌ ์ฌ์ฉ์์ ์ธ์ฆ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.memberId ํ๋๋ฅผ authentication.getName()์์ ์ป์ ๊ฐ์ Integer๋ก ๋ณํํ์ฌ ์ค์ ํฉ๋๋ค.BoardMapper.java
@Insert("""
INSERT INTO board (title, content, member_id)
VALUES (#{title}, #{content}, #{memberId})
""")
int insert(Board board);
BoardMapper.java
@Select("""
SELECT b.id, b.title , m.nick_name writer
FROM board b JOIN member m
ON b.member_id = m.id
ORDER BY b.id DESC
""")
List<Board> selectAll();
2. ํด๋น id ๊ฒ์๊ธ ์กฐํ
BoardMapper.java
@Select("""
SELECT b.id,
b.title,
b.content,
b.inserted,
m.nick_name writer
FROM board b JOIN member m ON b.member_id = m.id
WHERE b.id = #{id}
""")
Board selectById(Integer id);
BoardController
@DeleteMapping("{id}")
@PreAuthorize("isAuthenticated()")
public ResponseEntity delete(@PathVariable Integer id,
Authentication authentication) {
if (service.hasAccess(id, authentication)) {
service.remove(id);
return ResponseEntity.ok().build();
}
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
@PreAuthorize("isAuthenticated()")๋ก ํ์ธํ๊ณ ๋ง์ฝ ๋ก๊ทธ์ธ ํ๋ค๋ฉด ํด๋น id์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง id๊ฐ ํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ณ์ ์ด ๋ง๋์ง ํ์ธํ๊ณ ๋ง๋ค๋ฉด ์๋น์ค์์ ํด๋น ๊ฒ์๊ธ์ ์ ๊ฑฐํด์ค๋๋ค.BoardService.java
public boolean hasAccess(Integer id, Authentication authentication) {
Board board = mapper.selectById(id); //๊ฒ์๋ฌผ ๋ฒํธ
return board.getMemberId().equals(Integer.valueOf(authentication.getName()));
}
board.getMemberId())์ ๊ณ์ ์ ์์ด๋(authentication.getName())๊ฐ ๊ฐ๋ค๋ฉด true๋ฅผ ๋ฐํํ๊ณ ์๋๋ฉด false๋ฅผ ๋ฐํํฉ๋๋ค.BoardMapper.java
@Select("""
SELECT b.id,
b.title,
b.content,
b.inserted,
m.nick_name writer,
b.member_id
FROM board b JOIN member m ON b.member_id = m.id
WHERE b.id = #{id}
""")
Board selectById(Integer id);
BoardView.jsx(React)
axios
.delete(`/api/board/${id}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
})
DELETE ์์ฒญ์ ํ ๋, Authorization ํค๋์ Bearer ํ ํฐ์ ํฌํจ์์ผ์ผ ํฉ๋๋ค. ์ด ํ ํฐ์ด ์์ด์ผ ์๋ฒ์์ ์์ฒญ์ ์ธ์ฆํ๊ณ ๊ถํ์ ํ์ธํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์, ํ ํฐ์ ๊ฐ์ด ๋ณด๋ด์ผ๋ง ์ฌ์ฉ์๊ฐ ํด๋น ๋ฆฌ์์ค์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง ๊ฒ์ฆํ ์ ์์ผ๋ฉฐ, ๊ถํ์ด ์๋ ๊ฒฝ์ฐ ์์ฒญ์ด ์ฒ๋ฆฌ๋ฉ๋๋ค.BoardController.java
@PutMapping("edit")
@PreAuthorize("isAuthenticated()")
public ResponseEntity edit(@RequestBody Board board, Authentication authentication) {
if (!service.hasAccess(board.getId(), authentication)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
if (service.validate(board)) { // ์ ๋ชฉ, ๋ด์ฉ ์ ํจ์ฑ ๊ฒ์ฌ
service.edit(board);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}
@PreAuthorize("isAuthenticated()")๋ก ํ์ธํ๊ณ ๋ง์ฝ ๋ก๊ทธ์ธ ํ๋ค๋ฉด ํด๋น board ๊ฐ์ฒด์ id์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง board ๊ฐ์ฒด์ id๊ฐ ํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ณ์ ์ด ๋ง๋์ง service์์ ํ์ธํ๊ณ ์๋๋ผ๋ฉด FORBIDDEN ์๋ต ์ฝ๋๋ฅผ ๋ฐํํฉ๋๋ค.BoardMapper.java
@Update("""
UPDATE board SET title=#{title}, content=#{content}
WHERE id=#{id}
""")
int update(Board board);
BoardEdit.jsx(React)
axios
.put("/api/board/edit", board, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
})
PUT ์์ฒญ์ ํ ๋, Authorization ํค๋์ Bearer ํ ํฐ์ ํฌํจ์์ผ์ผ ํฉ๋๋ค. ์ด ํ ํฐ์ด ์์ด์ผ ์๋ฒ์์ ์์ฒญ์ ์ธ์ฆํ๊ณ ๊ถํ์ ํ์ธํ ์ ์์ต๋๋ค. - ์์ ์ ๊ฒ์๊ธ์ด๋ผ๋ฉด, ํด๋น ๊ถํ์ด ์๋ค๋ฉด ์์ , ์ญ์ ๋ฒํผ์ ๋ณด์ด๊ฒ ํฉ๋๋ค.
---
### ๐ **์์ ์ ํ์ ์ ๋ณด๋ง ์ด๋(READ)**
<br>
**Member.jsx(React)**
```java
axios
.get(`/api/member/${id}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
})
if (err.response.status === 403) {
toast({
status: "error",
description: "์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค.",
position: "top-right",
duration: 1000,
});
navigate(-1); //์ด์ ํ๋ฉด
}
GET ์์ฒญ์ ํ ๋, Authorization ํค๋์ Bearer ํ ํฐ์ ํฌํจ์์ผ์ผ ํฉ๋๋ค. ์ด ํ ํฐ์ด ์์ด์ผ ์๋ฒ์์ ์์ฒญ์ ์ธ์ฆํ๊ณ ๊ถํ์ ํ์ธํ ์ ์์ต๋๋ค. MemberController.java
@GetMapping("{id}")
@PreAuthorize("isAuthenticated()")
public ResponseEntity get(@PathVariable Integer id, Authentication authentication) {
if (!service.hasAccess(id, authentication)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
Member member = service.get(id);
if (member == null) {
return ResponseEntity.notFound().build();
} else {
return ResponseEntity.ok().body(member);
}
}
@PreAuthorize("isAuthenticated()")๋ก ํ์ธํ๊ณ ๋ง์ฝ ๋ก๊ทธ์ธ ํ๋ค๋ฉด ํด๋น id์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง id๊ฐ ํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ณ์ ์ด ๋ง๋์ง ์๋น์ค์์ ํ์ธํฉ๋๋ค. ๋ง์ฝ ์๋๋ผ๋ฉด FORBIDDEN ์๋ต ์ฝ๋๋ฅผ ๋ฐํํฉ๋๋ค.MemberService.java
public boolean hasAccess(Integer id, Authentication authentication) {
return authentication.getName().equals(id.toString());
}
authentication ๊ฐ์ฒด์ ์ด๋ฆ)์ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ฃผ์ด์ง id๋ฅผ ๋น๊ตํฉ๋๋ค.MemberController.java
@PutMapping("modify")
@PreAuthorize("isAuthenticated()")
public ResponseEntity modify(@RequestBody Member member, Authentication authentication) {
if (service.hasAccessModify(member, authentication)) {
service.modify(member);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
}
@PreAuthorize("isAuthenticated()")๋ก ํ์ธํ๊ณ ๋ง์ฝ ๋ก๊ทธ์ธ ํ๋ค๋ฉด member ๊ฐ์ฒด์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง member ๊ฐ์ฒด๊ฐ ํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ณ์ ์ด ๋ง๋ค๋ฉด ์๋น์ค์์ ํด๋น member ์ ๋ณด๋ฅผ ์์ ํฉ๋๋ค.MemberService.java
public boolean hasAccessModify(Member member, Authentication authentication) {
if (!authentication.getName().equals(member.getId().toString())) {
return false;
}
~~~
}
Member ๊ฐ์ฒด์ ID๋ฅผ ๋ฌธ์๋กค ๋ณํํ์ฌ ๋ ๊ฐ์ ๋น๊ตํฉ๋๋ค. MemberController.java
@DeleteMapping("{id}")
@PreAuthorize("isAuthenticated()")
public ResponseEntity delete(@RequestBody Member member,
Authentication authentication) {
if (service.hasAccess(member, authentication)) {
service.delete(member.getId());
return ResponseEntity.ok().build();
}
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
@PreAuthorize("isAuthenticated()")๋ก ํ์ธํ๊ณ ๋ง์ฝ ๋ก๊ทธ์ธ ํ๋ค๋ฉด ํด๋น member์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง member๊ฐ ํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ณ์ ์ด ๋ง๋์ง ํ์ธํ๊ณ ๋ง๋ค๋ฉด ์๋น์ค์์ ์์ ์ ๊ณ์ ์ ํํดํฉ๋๋ค.MemberService.java
public boolean hasAccess(Member member, Authentication authentication) {
if (!member.getId().toString().equals(authentication.getName())) {
return false;
}
Member dbMember = mapper.selectById(member.getId());
if (dbMember == null) {
return false;
}
return passwordEncoder.matches(member.getPassword(), dbMember.getPassword());
}
authentication.getName()(์ฌ์ฉ์์ ID)์ member ๊ฐ์ฒด์ ID๊ฐ ๋ค๋ฅด๋ฉด ์ ๊ทผ ๊ถํ์ด ์์ false๋ก ๋ฐํํ๊ณ DB์ ํด๋น ๋ฉค๋ฒ์ ID๊ฐ ์กฐํ๋์ง ์์๋ false๋ก ๋ฐํํ๊ณ ์กฐํ๋์ด ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋น๋ฐ๋ฒํธํ DB์ ์กฐํ๋ ๋ฉค๋ฒ์ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ผ๋ฉด false๋ฅผ ๋ฐํํ์ฌ ๊ถํ์ด ์์์ ๋ํ๋
๋๋ค.MemberView.jsx(React)
const account = useContext(LoginContext);
function handleDeleteClick() {
setIsLoading(true);
axios
.delete(`/api/member/${id}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
data: { id, password },
})
.then((res) => {
toast({
status: "success",
description: `${member.id}๋์ด ํํดํ์์ต๋๋ค. `,
position: "top-right",
duration: 1000,
});
account.logout();
navigate("/");
})
.catch((err) => {
toast({
status: "error",
description: `์ฌ๋ฐ๋ฅธ ๋น๋ฐ๋ฒํธ๊ฐ ์๋๋๋ค.`,
position: "top-right",
duration: 1000,
});
})
.finally(() => {
setIsLoading(false);
setPassword("");
onClose();
});
}
account.logout() : ํํด์ ๋ก๊ทธ์์ ๋๊ฒ ํฉ๋๋ค.๐ฅน ํ์ ์ญ์ ์, ์ด๋ฏธ ๊ฒ์๊ธ์ด ์๋ ํ์์ ์ญ์ ๊ฐ ์๋จ...
MemberService.java
public void delete(Integer id) {
// board ํ
์ด๋ธ์์ ์์ฑํ ๊ธ ์ง์ฐ๊ธฐ
boardMapper.deleteByMemberId(id);
// board ์ง์ด ํ member ํ
์ด๋ธ ์ง์ฐ๊ธฐ
mapper.deleteById(id);
}
BoardMapper.java
@Delete("""
DELETE FROM board
WHERE member_id=#{memberId}
""")
int deleteByMemberId(Integer memberId);
axios ํ ํฐ์ ๊ณ์ํด์ ์ถ๊ฐ์์ผ์ค์ผ ํ๋ ๋ฒ๊ฑฐ๋ก์ App.jsx ํ์ผ์ axios interceptor ์ค์ ์ ํด์ฃผ์๋ค.
// axios interceptor ์ค์
axios.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.authorization = `Bearer ${token}`;
}
return config;
});