\ud604\ub300\uc758 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc740 \uc0ac\uc6a9\uc790 \uc778\uc99d \ubc0f \uad8c\ud55c \ubd80\uc5ec\ub97c \uc704\ud55c \uac15\ub825\ud55c \ubcf4\uc548 \uba54\ucee4\ub2c8\uc998\uc744 \ud544\uc694\ub85c \ud569\ub2c8\ub2e4. \ud2b9\ud788, Spring Boot\uc640 \uac19\uc740 \ud504\ub808\uc784\uc6cc\ud06c\ub97c \uc0ac\uc6a9\ud560 \ub54c, JWT(Json Web Token)\uc640 OAuth2\ub294 \ub9e4\uc6b0 \uc911\uc694\ud55c \uc5ed\ud560\uc744 \ud569\ub2c8\ub2e4. \uc774 \uae00\uc5d0\uc11c\ub294 Spring Boot\uc5d0\uc11c JWT\uc640 OAuth2\ub97c \ud65c\uc6a9\ud55c \ucee4\uc2a4\ud130\ub9c8\uc774\uc988\ub41c \ubcf4\uc548 \ud328\ud134\uc5d0 \ub300\ud574 \uae4a\uc774 \uc788\uac8c \ub2e4\ub8e8\uc5b4 \ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n
\uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ubcf4\uc548\uc740 \uc0ac\uc6a9\uc790 \ub370\uc774\ud130 \ubcf4\ud638\uc640 \uc2e0\ub8b0\uc131 \ud655\ubcf4\ub97c \uc704\ud574 \ud544\uc218\uc801\uc785\ub2c8\ub2e4. \ud574\ud0b9, \ub370\uc774\ud130 \uc720\ucd9c, \uc11c\ube44\uc2a4 \uac70\ubd80 \uacf5\uaca9(DoS) \ub4f1 \ub2e4\uc591\ud55c \uc704\ud611\uc774 \uc874\uc7ac\ud558\ub294 \uac00\uc6b4\ub370, \ud6a8\uacfc\uc801\uc778 \ubcf4\uc548 \uc804\ub7b5\uc774 \ud544\uc694\ud569\ub2c8\ub2e4. \ud2b9\ud788, \uc0ac\uc6a9\uc790 \uc778\uc99d\uacfc \uad8c\ud55c \ubd80\uc5ec\ub294 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ud575\uc2ec \uc694\uc18c\ub85c, \uc774\ub97c \ud1b5\ud574 \uc0ac\uc6a9\uc790\uc758 \uc2e0\uc6d0\uc744 \ud655\uc778\ud558\uace0 \uc801\uc808\ud55c \uc811\uadfc \uad8c\ud55c\uc744 \ubd80\uc5ec\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n
\ubcf4\uc548\uc758 \uc911\uc694\uc131\uc744 \uac15\uc870\ud558\uae30 \uc704\ud574 \uba87 \uac00\uc9c0 \ud1b5\uacc4\ub97c \uc0b4\ud3b4\ubcf4\uaca0\uc2b5\ub2c8\ub2e4. 2021\ub144 IBM\uc758 \ubcf4\uace0\uc11c\uc5d0 \ub530\ub974\uba74, \ub370\uc774\ud130 \uc720\ucd9c \uc0ac\uac74\uc758 \ud3c9\uade0 \ube44\uc6a9\uc740 \uc57d 4.24\ubc31\ub9cc \ub2ec\ub7ec\uc5d0 \ub2ec\ud558\uba70, \uc774\ub294 \uae30\uc5c5\uc758 \uc7ac\uc815\uc801 \uc190\uc2e4\ubfd0\ub9cc \uc544\ub2c8\ub77c \ube0c\ub79c\ub4dc \uc2e0\ub8b0\ub3c4\uc5d0\ub3c4 \ud070 \uc601\ud5a5\uc744 \ubbf8\uce69\ub2c8\ub2e4. \ub530\ub77c\uc11c, \ud6a8\uacfc\uc801\uc778 \ubcf4\uc548 \uc194\ub8e8\uc158\uc744 \uad6c\ud604\ud558\ub294 \uac83\uc740 \uae30\uc5c5\uc758 \uc0dd\uc874\uacfc \uc9c1\uacb0\ub429\ub2c8\ub2e4.<\/p>\n
Spring Boot\ub294 \uc774\ub7ec\ud55c \ubcf4\uc548 \uc694\uad6c \uc0ac\ud56d\uc744 \ucda9\uc871\ud558\uae30 \uc704\ud574 \ub2e4\uc591\ud55c \uae30\ub2a5\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. \ud2b9\ud788, JWT\uc640 OAuth2\ub294 \ud604\ub300 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc5d0\uc11c \ub110\ub9ac \uc0ac\uc6a9\ub418\ub294 \uc778\uc99d \ubc0f \uad8c\ud55c \ubd80\uc5ec \uba54\ucee4\ub2c8\uc998\uc73c\ub85c \uc790\ub9ac \uc7a1\uace0 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n
JWT\ub294 JSON Web Token\uc758 \uc57d\uc790\ub85c, \uc0ac\uc6a9\uc790 \uc778\uc99d \uc815\ubcf4\ub97c \uc548\uc804\ud558\uac8c \uc804\uc1a1\ud558\uae30 \uc704\ud55c \uac1c\ubc29\ud615 \ud45c\uc900\uc785\ub2c8\ub2e4. JWT\ub294 \uc138 \ubd80\ubd84\uc73c\ub85c \uad6c\uc131\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4: \ud5e4\ub354(header), \ud398\uc774\ub85c\ub4dc(payload), \uc11c\uba85(signature)\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c \uad6c\uc870 \ub355\ubd84\uc5d0 JWT\ub294 \uac04\ud3b8\ud558\uac8c \uc815\ubcf4\ub97c \uc804\uc1a1\ud560 \uc218 \uc788\uc73c\uba70, \uc11c\ubc84\uc640 \ud074\ub77c\uc774\uc5b8\ud2b8 \uac04\uc758 \uc0c1\ud0dc\ub97c \uc720\uc9c0\ud560 \ud544\uc694\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n
JWT\uc758 \uc8fc\uc694 \uc7a5\uc810 \uc911 \ud558\ub098\ub294 Stateless Authentication\uc744 \uc9c0\uc6d0\ud55c\ub2e4\ub294 \uc810\uc785\ub2c8\ub2e4. \uc11c\ubc84\ub294 \ud074\ub77c\uc774\uc5b8\ud2b8\uc758 \uc0c1\ud0dc\ub97c \uc800\uc7a5\ud560 \ud544\uc694\uac00 \uc5c6\uc73c\uba70, \ud074\ub77c\uc774\uc5b8\ud2b8\ub294 JWT\ub97c \ud1b5\ud574 \uc778\uc99d \uc815\ubcf4\ub97c \uc720\uc9c0\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774\ub294 \ud655\uc7a5\uc131\uacfc \uc131\ub2a5 \uce21\uba74\uc5d0\uc11c \ud070 \uc774\uc810\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n
OAuth2\ub294 \uc778\uc99d \ubc0f \uad8c\ud55c \ubd80\uc5ec\ub97c \uc704\ud55c \ud504\ub85c\ud1a0\ucf5c\ub85c, \uc0ac\uc6a9\uc790\uac00 \uc790\uc2e0\uc758 \uc790\uc6d0\uc5d0 \ub300\ud55c \uc811\uadfc \uad8c\ud55c\uc744 \uc81c3\uc790\uc5d0\uac8c \uc548\uc804\ud558\uac8c \ubd80\uc5ec\ud560 \uc218 \uc788\ub3c4\ub85d \ud569\ub2c8\ub2e4. OAuth2\ub294 \ub2e4\uc591\ud55c \uc778\uc99d \ud750\ub984\uc744 \uc81c\uacf5\ud558\uc5ec \ub2e4\uc591\ud55c \uc0ac\uc6a9 \uc0ac\ub840\uc5d0 \uc801\ud569\ud569\ub2c8\ub2e4. \ub300\ud45c\uc801\uc778 \ud750\ub984\uc73c\ub85c\ub294 Authorization Code Flow, Implicit Flow, Resource Owner Password Credentials Flow \ub4f1\uc774 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n
OAuth2\uc758 \uc8fc\uc694 \uad6c\uc131 \uc694\uc18c\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4:<\/p>\n
OAuth2\ub294 \ub2e4\uc591\ud55c \ud50c\ub7ab\ud3fc\uacfc \uc11c\ube44\uc2a4\uc5d0\uc11c \ub110\ub9ac \uc0ac\uc6a9\ub418\uba70, \ud2b9\ud788 \uc18c\uc15c \ub85c\uadf8\uc778 \uae30\ub2a5\uc744 \uad6c\ud604\ud560 \ub54c \uc720\uc6a9\ud569\ub2c8\ub2e4. \uc608\ub97c \ub4e4\uc5b4, \uc0ac\uc6a9\uc790\uac00 Google \uacc4\uc815\uc744 \ud1b5\ud574 \uc6f9\uc0ac\uc774\ud2b8\uc5d0 \ub85c\uadf8\uc778\ud560 \uc218 \uc788\ub3c4\ub85d \ud558\ub294 \uac83\uc774 \uac00\ub2a5\ud569\ub2c8\ub2e4.<\/p>\n
Spring Boot\uc5d0\uc11c JWT\ub97c \uad6c\ud604\ud558\ub294 \uacfc\uc815\uc740 \ube44\uad50\uc801 \uac04\ub2e8\ud569\ub2c8\ub2e4. \uba3c\uc800, \ud544\uc694\ud55c \uc758\uc874\uc131\uc744 \ucd94\uac00\ud574\uc57c \ud569\ub2c8\ub2e4. Maven\uc744 \uc0ac\uc6a9\ud558\ub294 \uacbd\uc6b0, \ub2e4\uc74c\uacfc \uac19\uc740 \uc758\uc874\uc131\uc744 pom.xml\uc5d0 \ucd94\uac00\ud569\ub2c8\ub2e4:<\/p>\n
\n\n io.jsonwebtoken\n jjwt\n 0.9.1\n\n<\/code><\/pre>\n\uadf8 \ub2e4\uc74c, JWT\ub97c \uc0dd\uc131\ud558\uace0 \uac80\uc99d\ud558\ub294 \uc720\ud2f8\ub9ac\ud2f0 \ud074\ub798\uc2a4\ub97c \uc791\uc131\ud569\ub2c8\ub2e4. \uc774 \ud074\ub798\uc2a4\ub294 JWT\uc758 \uc0dd\uc131, \ud30c\uc2f1 \ubc0f \uac80\uc99d\uc744 \ub2f4\ub2f9\ud569\ub2c8\ub2e4.<\/p>\n
\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Component\npublic class JwtUtil {\n private String secretKey = \"mySecretKey\";\n\n public String generateToken(String username) {\n Map claims = new HashMap();\n return createToken(claims, username);\n }\n\n private String createToken(Map claims, String subject) {\n return Jwts.builder()\n .setClaims(claims)\n .setSubject(subject)\n .setIssuedAt(new Date(System.currentTimeMillis()))\n .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) \/\/ 10\uc2dc\uac04\n .signWith(SignatureAlgorithm.HS256, secretKey)\n .compact();\n }\n\n public Boolean validateToken(String token, String username) {\n final String extractedUsername = extractUsername(token);\n return (extractedUsername.equals(username) && !isTokenExpired(token));\n }\n\n private String extractUsername(String token) {\n return extractAllClaims(token).getSubject();\n }\n\n private Claims extractAllClaims(String token) {\n return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();\n }\n\n private Boolean isTokenExpired(String token) {\n return extractAllClaims(token).getExpiration().before(new Date());\n }\n}\n<\/code><\/pre>\n\uc704\uc758 \ucf54\ub4dc\uc5d0\uc11c JwtUtil \ud074\ub798\uc2a4\ub294 JWT\ub97c \uc0dd\uc131\ud558\uace0 \uac80\uc99d\ud558\ub294 \uba54\uc11c\ub4dc\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uc774\uc81c \uc774 \ud074\ub798\uc2a4\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc0ac\uc6a9\uc790 \uc778\uc99d\uc744 \ucc98\ub9ac\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n
5. Spring Security\uc640 JWT \ud1b5\ud569\ud558\uae30<\/h2>\n
Spring Security\ub294 Spring Boot \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc758 \ubcf4\uc548\uc744 \uac15\ud654\ud558\ub294 \ub370 \ud544\uc218\uc801\uc778 \uc694\uc18c\uc785\ub2c8\ub2e4. JWT\ub97c Spring Security\uc640 \ud1b5\ud569\ud558\uba74 \ub354\uc6b1 \uac15\ub825\ud55c \ubcf4\uc548 \uc194\ub8e8\uc158\uc744 \uad6c\ucd95\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774\ub97c \uc704\ud574 SecurityFilterChain\uc744 \uc124\uc815\ud558\uace0 JWT \ud544\ud130\ub97c \ucd94\uac00\ud574\uc57c \ud569\ub2c8\ub2e4.<\/p>\n
\nimport org.springframework.context.annotation.Bean;
\nimport org.springframework.security.authentication.AuthenticationManager;
\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;
\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
\nimport org.springframework.security.config.http.SessionCreationPolicy;
\nimport org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;<\/p>\n@EnableWebSecurity
\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {<\/p>\n
@Autowired
\n private JwtRequestFilter jwtRequestFilter;<\/p>\n
@Override
\n protected void configure(HttpSecurity http) throws Exception {
\n http<\/p>\n","protected":false},"excerpt":{"rendered":"
\ubaa9\ucc28 Spring Boot\uc5d0\uc11c\uc758 \ucee4\uc2a4\ud130\ub9c8\uc774\uc988\ub41c \ubcf4\uc548 \ud328\ud134: JWT\uc640 OAuth2 1. \ubcf4\uc548\uc758 \uc911\uc694\uc131 2. JWT\ub780 \ubb34\uc5c7\uc778\uac00? 3. […]<\/p>\n","protected":false},"author":1,"featured_media":33704,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1957],"tags":[2014,190,2079],"class_list":["post-50561","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-code","tag-google","tag-security"],"acf":[],"_links":{"self":[{"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/posts\/50561","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/comments?post=50561"}],"version-history":[{"count":0,"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/posts\/50561\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/media\/33704"}],"wp:attachment":[{"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/media?parent=50561"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/categories?post=50561"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/m9js.shop\/blog\/wp-json\/wp\/v2\/tags?post=50561"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}