Skip to content

Commit

Permalink
Merge pull request #23 from wwan13/feature/jwt
Browse files Browse the repository at this point in the history
scan payload
  • Loading branch information
wwan13 authored Jun 7, 2024
2 parents 3a40b43 + 5ba75ee commit a273223
Show file tree
Hide file tree
Showing 27 changed files with 254 additions and 246 deletions.
41 changes: 22 additions & 19 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.13'
id 'io.spring.dependency-management' version '1.1.4'
id 'java'
id 'org.springframework.boot' version '2.7.13'
id 'io.spring.dependency-management' version '1.1.4'
}

group = 'io.wwan13'
version = '0.0.1'

java {
sourceCompatibility = '17'
sourceCompatibility = '17'
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
// spring
implementation 'org.springframework.boot:spring-boot-starter'
// spring
implementation 'org.springframework.boot:spring-boot-starter'

// web
implementation 'org.springframework.boot:spring-boot-starter-web'
// web
implementation 'org.springframework.boot:spring-boot-starter-web'

// jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
// jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

// password encoder
implementation 'org.springframework.security:spring-security-crypto:6.1.0'
// password encoder
implementation 'org.springframework.security:spring-security-crypto:6.1.0'

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.junit.jupiter:junit-jupiter'
// reflections api
implementation 'org.reflections:reflections:0.9.10'

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.junit.jupiter:junit-jupiter'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import io.wwan13.wintersecurity.jwt.PayloadAnalysis;
import io.wwan13.wintersecurity.jwt.PayloadAnalyst;
import io.wwan13.wintersecurity.jwt.PayloadParser;
import io.wwan13.wintersecurity.jwt.PayloadScanner;
import io.wwan13.wintersecurity.jwt.TokenDecoder;
import io.wwan13.wintersecurity.jwt.TokenGenerator;
import io.wwan13.wintersecurity.jwt.payload.support.JwtPayloadParser;
import io.wwan13.wintersecurity.jwt.payload.support.ReflectionPayloadAnalyst;
import io.wwan13.wintersecurity.jwt.payload.support.DefaultPayloadAnalyst;
import io.wwan13.wintersecurity.jwt.payload.support.ReflectionPayloadScanner;
import io.wwan13.wintersecurity.jwt.provider.JwtTokenDecoder;
import io.wwan13.wintersecurity.jwt.provider.JwtTokenGenerator;
import io.wwan13.wintersecurity.secretkey.SecretKey;
Expand All @@ -47,8 +49,11 @@ public TokenDecoder tokenDecoder(SecretKey secretKey) {

@Bean
public PayloadAnalysis payloadAnalysis(JwtProperties jwtProperties) {
PayloadAnalyst payloadAnalyst = new ReflectionPayloadAnalyst();
return payloadAnalyst.analyze(jwtProperties);
PayloadScanner payloadScanner = new ReflectionPayloadScanner();
PayloadAnalyst payloadAnalyst = new DefaultPayloadAnalyst();

Class<?> scannedPayload = payloadScanner.scan();
return payloadAnalyst.analyze(scannedPayload);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@

package io.wwan13.wintersecurity.constant;

import io.wwan13.wintersecurity.jwt.Payload;
import io.wwan13.wintersecurity.jwt.payload.DefaultPayload;

public class Constants {

// Default Option
public static final long DEFAULT_ACCESS_TOKEN_VALIDITY = 10000;
public static final long DEFAULT_REFRESH_TOKEN_VALIDITY = 10000;
public static final Class<? extends Payload> DEFAULT_PAYLOAD_CLAZZ = DefaultPayload.class;
public static final Class<?> DEFAULT_SUBJECT_CLAZZ = Object.class;

// Payload
public static final String PAYLOAD_KEY_TOKEN_TYPE = "token_type";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

public record JwtProperties(
long accessTokenValidity,
long refreshTokenValidity,
Class<? extends Payload> payloadClazz,
Class<?> subjectClazz
long refreshTokenValidity
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.Set;

public record PayloadAnalysis(
Class<? extends Payload> payloadClazz,
Class<?> payloadClazz,
Field subject,
Field roles,
Set<Field> additionalClaims
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@

public interface PayloadAnalyst {

PayloadAnalysis analyze(JwtProperties jwtProperties);
PayloadAnalysis analyze(Class<?> payloadClazz);
}
8 changes: 5 additions & 3 deletions src/main/java/io/wwan13/wintersecurity/jwt/PayloadParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

public interface PayloadParser {

String asSubject(Payload payload);
Set<String> asRoles(Payload payload);
Map<String, Object> asAdditionalClaims(Payload payload);
String asSubject(Object payload);

Set<String> asRoles(Object payload);

Map<String, Object> asAdditionalClaims(Object payload);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,7 @@

package io.wwan13.wintersecurity.jwt;

import io.wwan13.wintersecurity.jwt.payload.DefaultPayload;
public interface PayloadScanner {

import java.util.Set;

public interface Payload {

static DefaultPayload of(Object subject, Set<Object> roles) {
return new DefaultPayload(subject, roles);
}
Class<?> scan();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package io.wwan13.wintersecurity.jwt;

public interface TokenGenerator {
String accessToken(Payload payload);
String refreshToken(Payload payload);

String accessToken(Object payload);

String refreshToken(Object payload);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@

package io.wwan13.wintersecurity.jwt.payload;

import io.wwan13.wintersecurity.jwt.Payload;
import io.wwan13.wintersecurity.jwt.payload.annotation.Roles;
import io.wwan13.wintersecurity.jwt.payload.annotation.Subject;

import java.util.Set;

public class DefaultPayload implements Payload {
public class DefaultPayload {

@Subject
private Object subject;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.wwan13.wintersecurity.jwt.payload.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Payload {
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package io.wwan13.wintersecurity.jwt.payload.support;

import io.wwan13.wintersecurity.jwt.JwtProperties;
import io.wwan13.wintersecurity.jwt.Payload;
import io.wwan13.wintersecurity.jwt.PayloadAnalysis;
import io.wwan13.wintersecurity.jwt.PayloadAnalyst;
import io.wwan13.wintersecurity.jwt.payload.annotation.Claim;
Expand All @@ -31,14 +29,12 @@
import java.util.Set;
import java.util.stream.Collectors;

public class ReflectionPayloadAnalyst implements PayloadAnalyst {
public class DefaultPayloadAnalyst implements PayloadAnalyst {

private static final int FIRST_ELEMENT_INDEX = 0;

@Override
public PayloadAnalysis analyze(JwtProperties jwtProperties) {
Class<? extends Payload> payloadClazz = jwtProperties.payloadClazz();

public PayloadAnalysis analyze(Class<?> payloadClazz) {
Field subject = findFieldByDeclaredAnnotation(payloadClazz, Subject.class);
Field roles = findFieldByDeclaredAnnotation(payloadClazz, Roles.class);
Set<Field> additionalClaims = findAdditionalClaimFields(payloadClazz);
Expand All @@ -47,7 +43,7 @@ public PayloadAnalysis analyze(JwtProperties jwtProperties) {
}

private Field findFieldByDeclaredAnnotation(
Class<? extends Payload> payloadClazz,
Class<?> payloadClazz,
Class<? extends Annotation> declared
) {
List<Field> fields = Arrays.stream(payloadClazz.getDeclaredFields())
Expand All @@ -72,7 +68,7 @@ private void validateExistsOnlyOne(
}

private Set<Field> findAdditionalClaimFields(
Class<? extends Payload> payloadClazz
Class<?> payloadClazz
) {
return Arrays.stream(payloadClazz.getDeclaredFields())
.filter(this::isAdditionalClaim)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.wwan13.wintersecurity.jwt.payload.support;

import io.wwan13.wintersecurity.jwt.Payload;
import io.wwan13.wintersecurity.jwt.PayloadAnalysis;
import io.wwan13.wintersecurity.jwt.PayloadParser;

Expand All @@ -38,13 +37,13 @@ public JwtPayloadParser(PayloadAnalysis payloadAnalysis) {
}

@Override
public String asSubject(Payload payload) {
public String asSubject(Object payload) {
Field field = payloadAnalysis.subject();
return Objects.toString(getFieldValue(payload, field));
}

@Override
public Set<String> asRoles(Payload payload) {
public Set<String> asRoles(Object payload) {
Field field = payloadAnalysis.roles();
Object values = getFieldValue(payload, field);

Expand All @@ -58,7 +57,7 @@ public Set<String> asRoles(Payload payload) {
}

@Override
public Map<String, Object> asAdditionalClaims(Payload payload) {
public Map<String, Object> asAdditionalClaims(Object payload) {
Set<Field> fields = payloadAnalysis.additionalClaims();
Map<String, Object> additionalClaims = new HashMap<>();

Expand All @@ -68,7 +67,7 @@ public Map<String, Object> asAdditionalClaims(Payload payload) {
return additionalClaims;
}

private Object getFieldValue(Payload payload, Field field) {
private Object getFieldValue(Object payload, Field field) {
try {
field.setAccessible(true);
return field.get(payload);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.wwan13.wintersecurity.jwt.payload.support;

import io.wwan13.wintersecurity.jwt.PayloadScanner;
import io.wwan13.wintersecurity.jwt.payload.DefaultPayload;
import io.wwan13.wintersecurity.jwt.payload.annotation.Payload;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;

import java.util.Set;

public class ReflectionPayloadScanner implements PayloadScanner {

private static final String DEFAULT_SCAN_BASE_PACKAGE = "";

@Override
public Class<?> scan() {
Reflections reflections = new Reflections(
DEFAULT_SCAN_BASE_PACKAGE,
new TypeAnnotationsScanner(),
new SubTypesScanner()
);

Set<Class<?>> payloads = reflections.getTypesAnnotatedWith(Payload.class);
validateMoreThanTwo(payloads);

return payloads.stream()
.findFirst()
.orElse(DefaultPayload.class);
}

public void validateMoreThanTwo(Set<Class<?>> payloads) {
if (payloads.size() > 1) {
throw new IllegalStateException("Must be only one payload.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import io.jsonwebtoken.Jwts;
import io.wwan13.wintersecurity.jwt.JwtProperties;
import io.wwan13.wintersecurity.jwt.Payload;
import io.wwan13.wintersecurity.jwt.PayloadParser;
import io.wwan13.wintersecurity.jwt.TokenGenerator;
import io.wwan13.wintersecurity.jwt.payload.util.RoleSerializer;
Expand Down Expand Up @@ -47,8 +46,7 @@ public JwtTokenGenerator(
}

@Override
public String accessToken(Payload payload) {
validatePayloadClazz(payload.getClass());
public String accessToken(Object payload) {
return Jwts.builder()
.setSubject(payloadParser.asSubject(payload))
.setIssuedAt(DateUtil.now())
Expand All @@ -61,8 +59,7 @@ public String accessToken(Payload payload) {
}

@Override
public String refreshToken(Payload payload) {
validatePayloadClazz(payload.getClass());
public String refreshToken(Object payload) {
return Jwts.builder()
.setSubject(payloadParser.asSubject(payload))
.setIssuedAt(DateUtil.now())
Expand All @@ -73,10 +70,4 @@ public String refreshToken(Payload payload) {
.signWith(secretKey.value())
.compact();
}

private void validatePayloadClazz(Class<? extends Payload> clazz) {
if (!clazz.equals(properties.payloadClazz())) {
throw new IllegalArgumentException("The type of payload between set and entered do not match.");
}
}
}
Loading

0 comments on commit a273223

Please sign in to comment.