AngularJs [JWT]와 함께 OAuth2를 사용하는 스프링 보안
소개
This blog post will demonstrate the spring-security & angular JS integration using JWT token. My previous blog explains how we can configure classes to integrate
spring security with angular. I recommend you to watch my previous video tutorial because this tutorial is an addition over that video.

Angular JS와 함께 OAuth2를 사용하는 스프링 보안
Jitendra Singh Bisht ・ 6월 27일 ・ 1분 읽기
그 비디오 자습서에서 JWT 토큰을 생성하기 위해 이 블로그에서 다시 작성할 토큰을 저장하기 위해 클래스
TokenStore
를 만들었습니다.사용된 기술
- Java
- Spring Boot
- Spring Security
- Angular JS 8
OAuth2 흐름의 시퀀스 다이어그램

Jwt토큰스토어
In that video tutorial I've created HashMap based token store. Now we're going to overwrite that class and will
create one JWT based implementation.
package com.demo.security.config;
import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.stereotype.Component;
import java.security.interfaces.ECPrivateKey;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class JwtTokenStore implements ITokenStore {
// 1
private final String tokenSignKey = "c5d4d70419bd4909a1e502812c6e1f2b";
// 2
private final String REG_ID = "clientRegistrationId";
private final String NAMED_KEY = "namedAttributeKey";
private final String AUTHORITIES = "authorities";
private final String ATTRIBUTES = "attributes";
// 3
public String generateToken( Authentication authentication ) throws Exception {
OAuth2AuthenticationToken token = ( OAuth2AuthenticationToken ) authentication;
DefaultOAuth2User userDetails = ( DefaultOAuth2User ) token.getPrincipal();
// 4
List<String> auths = userDetails.getAuthorities()
.stream()
.map( GrantedAuthority::getAuthority )
.collect( Collectors.toList());
// 5
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject( userDetails.getAttribute("id").toString())
.expirationTime( getDate( 5, ChronoUnit.HOURS ) )
.claim( NAMED_KEY, "name" )
.claim( ATTRIBUTES, userDetails.getAttributes() )
.claim( AUTHORITIES, auths )
.claim( REG_ID, token.getAuthorizedClientRegistrationId() )
.build();
// 6
ECKey key = new ECKeyGenerator( Curve.P_256 ).keyID( tokenSignKey ).generate();
JWSHeader h = new JWSHeader.Builder( JWSAlgorithm.ES256 )
.type( JOSEObjectType.JWT )
.keyID( key.getKeyID() )
.build();
SignedJWT jwt = new SignedJWT( h, claimsSet );
// 7
jwt.sign( new ECDSASigner( ( ECPrivateKey ) key.toPrivateKey() ) );
return jwt.serialize();
}
// 8
public Authentication getAuth( String jwt ) throws Exception {
SignedJWT signedJWT = SignedJWT.parse( jwt );
// 9
validateJwt( signedJWT );
JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
// 10
String clientRegistrationId = (String ) claimsSet.getClaim( REG_ID );
String namedAttributeKey = (String) claimsSet.getClaim( NAMED_KEY );
Map<String, Object> attributes = (Map<String, Object>)claimsSet.getClaim( ATTRIBUTES );
Collection<? extends GrantedAuthority > authorities =( (List<String> ) claimsSet.getClaim( AUTHORITIES ))
.stream().map( SimpleGrantedAuthority::new ).collect( Collectors.toSet());
// 11
return new OAuth2AuthenticationToken(
new DefaultOAuth2User( authorities, attributes, namedAttributeKey ),
authorities,
clientRegistrationId
);
}
private static Date getDate( long amount, TemporalUnit unit ) {
return Date.from(
LocalDateTime.now()
.plus( amount, unit )
.atZone( ZoneId.systemDefault() )
.toInstant()
);
}
private void validateJwt( JWT jwt ) throws Exception {
// 12
if(jwt.getJWTClaimsSet().getExpirationTime().before( new Date() )){
throw new RuntimeException("Token Expired!!");
}
// Add validation logic here..
}
}
In the above code base I have added comment numbers which I am going to explain here.
- Token sign key will be used to sign the JWT. You can use your own key.
- Attributes which I'm going to get from Authentication object and will put them in the JWT which I'll be using later on to construct the Authentication Object.
- The generateToken method will accept Authentication object and build JWT token from that.
- Collecting all the authorities name.
- Preparing JWT claims with values like Subject, Authorities, Attributes, NamedAttributeKey (required by DefaultOAuth2User), and token expire time
- Prepare Sign key to Sign the JWT token.
- Sign the token and return.
- The getAuth method takes JWT token and prepares the Authentication object from the valid token.
- Validating the JWT token currently I'm validating the expireTime only, but you can add your custom validation logic.
- Get required objects from JWT claims which will be used to prepare Authentication token.
- Prepare and return the valid
OAuth2AuthenticationToken
. - Validating the expirationTime with current time.
Reference
이 문제에 관하여(AngularJs [JWT]와 함께 OAuth2를 사용하는 스프링 보안), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jeetmp3/spring-security-using-oauth2-with-angularjs-jwt-4nmd텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)