OAuth 2を用いたSpringセキュリティ
導入
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.
角度JSによるOAuS 2を用いたスプリングセキュリティ
ジットドラシンビシュット・ ジュン27・ 1分読む
私が作成したそのビデオチュートリアルで
TokenStore
JWTトークンを生成するためにこのブログで再書き込みするトークンを格納するクラス.使用技術
- Java
- Spring Boot
- Spring Security
- Angular JS 8
OAuS 2流のシーケンス図
JWTTokenStore
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
この問題について(OAuth 2を用いたSpringセキュリティ), 我々は、より多くの情報をここで見つけました https://dev.to/jeetmp3/spring-security-using-oauth2-with-angularjs-jwt-4nmdテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol