mirror of https://github.com/halo-dev/halo
Refactor PAT authentication by making it standalone (#6878)
#### What type of PR is this? /kind improvement /area core /milestone 2.20.x #### What this PR does / why we need it: This PR makes PAT configuration standalone and removes unused configuration related with `JWT`. After this, we can define additional authentications in plugins with correct configuration order. #### Does this PR introduce a user-facing change? ```release-note None ```pull/6885/head
parent
db4e68b732
commit
514a05552f
|
@ -1,6 +1,5 @@
|
|||
package run.halo.app.infra.config;
|
||||
|
||||
import static org.springframework.security.web.server.authentication.ServerWebExchangeDelegatingReactiveAuthenticationManagerResolver.builder;
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -33,8 +32,6 @@ import run.halo.app.security.HaloServerRequestCache;
|
|||
import run.halo.app.security.authentication.CryptoService;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
import run.halo.app.security.authentication.impl.RsaKeyService;
|
||||
import run.halo.app.security.authentication.pat.PatAuthenticationManager;
|
||||
import run.halo.app.security.authentication.pat.PatServerWebExchangeMatcher;
|
||||
import run.halo.app.security.authorization.AuthorityUtils;
|
||||
import run.halo.app.security.session.InMemoryReactiveIndexedSessionRepository;
|
||||
import run.halo.app.security.session.ReactiveIndexedSessionRepository;
|
||||
|
@ -86,15 +83,6 @@ public class WebServerSecurityConfig {
|
|||
basic.disable();
|
||||
}
|
||||
})
|
||||
.oauth2ResourceServer(oauth2 -> {
|
||||
var authManagerResolver = builder().add(
|
||||
new PatServerWebExchangeMatcher(),
|
||||
new PatAuthenticationManager(client, cryptoService)
|
||||
)
|
||||
// TODO Add other authentication mangers here. e.g.: JwtAuthenticationManager.
|
||||
.build();
|
||||
oauth2.authenticationManagerResolver(authManagerResolver);
|
||||
})
|
||||
.headers(headerSpec -> headerSpec
|
||||
.frameOptions(frameSpec -> {
|
||||
var frameOptions = haloProperties.getSecurity().getFrameOptions();
|
||||
|
|
|
@ -11,6 +11,7 @@ import static org.springframework.security.config.web.server.SecurityWebFiltersO
|
|||
import lombok.Setter;
|
||||
import org.pf4j.ExtensionPoint;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.WebFilterChainProxy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -22,6 +23,8 @@ import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
|||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
@Component
|
||||
// Specific an order here to control the order or security configurer initialization
|
||||
@Order(-100)
|
||||
public class SecurityWebFiltersConfigurer implements SecurityConfigurer {
|
||||
|
||||
private final ExtensionGetter extensionGetter;
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package run.halo.app.security.authentication.jwt;
|
||||
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
|
||||
import org.springframework.security.web.server.util.matcher.AndServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.MediaTypeServerWebExchangeMatcher;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import run.halo.app.infra.properties.JwtProperties;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
/**
|
||||
* TODO: Use It after 2.0.0.
|
||||
*/
|
||||
public class JwtAuthenticationConfigurer implements SecurityConfigurer {
|
||||
|
||||
private final ReactiveUserDetailsService userDetailsService;
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
private final ServerCodecConfigurer codec;
|
||||
|
||||
private final JwtEncoder jwtEncoder;
|
||||
|
||||
private final ServerResponse.Context context;
|
||||
|
||||
private final JwtProperties jwtProp;
|
||||
|
||||
public JwtAuthenticationConfigurer(ReactiveUserDetailsService userDetailsService,
|
||||
PasswordEncoder passwordEncoder,
|
||||
ServerCodecConfigurer codec,
|
||||
JwtEncoder jwtEncoder,
|
||||
ServerResponse.Context context,
|
||||
JwtProperties jwtProp) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.codec = codec;
|
||||
this.jwtEncoder = jwtEncoder;
|
||||
this.context = context;
|
||||
this.jwtProp = jwtProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ServerHttpSecurity http) {
|
||||
var loginManager = new LoginAuthenticationManager(userDetailsService, passwordEncoder);
|
||||
|
||||
var filter = new AuthenticationWebFilter(loginManager);
|
||||
var loginMatcher = new AndServerWebExchangeMatcher(
|
||||
pathMatchers(HttpMethod.POST, "/api/auth/token"),
|
||||
new MediaTypeServerWebExchangeMatcher(MediaType.APPLICATION_JSON)
|
||||
);
|
||||
|
||||
filter.setRequiresAuthenticationMatcher(loginMatcher);
|
||||
filter.setServerAuthenticationConverter(
|
||||
new LoginAuthenticationConverter(codec.getReaders()));
|
||||
filter.setAuthenticationSuccessHandler(
|
||||
new LoginAuthenticationSuccessHandler(jwtEncoder, jwtProp, context));
|
||||
filter.setAuthenticationFailureHandler(new LoginAuthenticationFailureHandler(context));
|
||||
|
||||
http.addFilterAt(filter, SecurityWebFiltersOrder.FORM_LOGIN);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package run.halo.app.security.authentication.jwt;
|
||||
|
||||
import static org.springframework.security.authentication.UsernamePasswordAuthenticationToken.unauthenticated;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class LoginAuthenticationConverter implements ServerAuthenticationConverter {
|
||||
|
||||
private final List<HttpMessageReader<?>> reader;
|
||||
|
||||
public LoginAuthenticationConverter(List<HttpMessageReader<?>> reader) {
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> convert(ServerWebExchange exchange) {
|
||||
return ServerRequest.create(exchange, this.reader)
|
||||
.bodyToMono(UsernamePasswordRequest.class)
|
||||
.map(request -> unauthenticated(request.getUsername(), request.getPassword()));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class UsernamePasswordRequest {
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package run.halo.app.security.authentication.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.server.WebFilterExchange;
|
||||
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class LoginAuthenticationFailureHandler implements ServerAuthenticationFailureHandler {
|
||||
|
||||
private final ServerResponse.Context context;
|
||||
|
||||
public LoginAuthenticationFailureHandler(ServerResponse.Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange,
|
||||
AuthenticationException exception) {
|
||||
return ServerResponse.badRequest()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(
|
||||
Map.of("error", exception.getLocalizedMessage())
|
||||
)
|
||||
.flatMap(serverResponse ->
|
||||
serverResponse.writeTo(webFilterExchange.getExchange(), context));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package run.halo.app.security.authentication.jwt;
|
||||
|
||||
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
public final class LoginAuthenticationManager
|
||||
extends UserDetailsRepositoryReactiveAuthenticationManager {
|
||||
|
||||
public LoginAuthenticationManager(ReactiveUserDetailsService userDetailsService,
|
||||
PasswordEncoder passwordEncoder) {
|
||||
super(userDetailsService);
|
||||
super.setPasswordEncoder(passwordEncoder);
|
||||
if (userDetailsService instanceof ReactiveUserDetailsPasswordService passwordService) {
|
||||
super.setUserDetailsPasswordService(passwordService);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package run.halo.app.security.authentication.jwt;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.jwt.JwsHeader;
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
|
||||
import org.springframework.security.web.server.WebFilterExchange;
|
||||
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.infra.properties.JwtProperties;
|
||||
|
||||
public class LoginAuthenticationSuccessHandler implements ServerAuthenticationSuccessHandler {
|
||||
|
||||
private final JwtEncoder jwtEncoder;
|
||||
|
||||
private final JwtProperties jwtProp;
|
||||
|
||||
private final ServerResponse.Context context;
|
||||
|
||||
public LoginAuthenticationSuccessHandler(JwtEncoder jwtEncoder, JwtProperties jwtProp,
|
||||
ServerResponse.Context context) {
|
||||
this.jwtEncoder = jwtEncoder;
|
||||
this.jwtProp = jwtProp;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange,
|
||||
Authentication authentication) {
|
||||
var issuedAt = Instant.now();
|
||||
// TODO Make the expiresAt configurable
|
||||
var expiresAt = issuedAt.plus(24, ChronoUnit.HOURS);
|
||||
var headers = JwsHeader.with(jwtProp.getJwsAlgorithm()).build();
|
||||
var claims = JwtClaimsSet.builder()
|
||||
.issuer("Halo Owner")
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
// the principal is the username
|
||||
.subject(authentication.getName())
|
||||
.claim("scope", authentication.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
|
||||
var jwt = jwtEncoder.encode(JwtEncoderParameters.from(headers, claims));
|
||||
|
||||
return ServerResponse.ok()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(Map.of("token", jwt.getTokenValue()))
|
||||
.flatMap(serverResponse -> serverResponse.writeTo(webFilterExchange.getExchange(),
|
||||
this.context));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package run.halo.app.security.authentication.pat;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.web.server.authentication.ServerBearerTokenAuthenticationConverter;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* PAT authentication converter.
|
||||
*
|
||||
* @author johnniang
|
||||
* @since 2.20.4
|
||||
*/
|
||||
class PatAuthenticationConverter extends ServerBearerTokenAuthenticationConverter {
|
||||
|
||||
public static final String PAT_TOKEN_PREFIX = "pat_";
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> convert(ServerWebExchange exchange) {
|
||||
return super.convert(exchange)
|
||||
.cast(BearerTokenAuthenticationToken.class)
|
||||
.map(BearerTokenAuthenticationToken::getToken)
|
||||
.filter(token -> StringUtils.startsWith(token, PAT_TOKEN_PREFIX))
|
||||
.map(token -> StringUtils.removeStart(token, PAT_TOKEN_PREFIX))
|
||||
.map(BearerTokenAuthenticationToken::new);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package run.halo.app.security.authentication.pat;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.removeStart;
|
||||
import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.withJwkSource;
|
||||
import static run.halo.app.security.authentication.pat.PatServerWebExchangeMatcher.PAT_TOKEN_PREFIX;
|
||||
import static run.halo.app.security.authorization.AuthorityUtils.ANONYMOUS_ROLE_NAME;
|
||||
import static run.halo.app.security.authorization.AuthorityUtils.AUTHENTICATED_ROLE_NAME;
|
||||
import static run.halo.app.security.authorization.AuthorityUtils.ROLE_PREFIX;
|
||||
|
@ -18,7 +16,6 @@ import org.springframework.security.authentication.ReactiveAuthenticationManager
|
|||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
@ -30,14 +27,14 @@ import run.halo.app.security.PersonalAccessToken;
|
|||
import run.halo.app.security.authentication.CryptoService;
|
||||
import run.halo.app.security.authorization.AuthorityUtils;
|
||||
|
||||
public class PatAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
class PatAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
|
||||
/**
|
||||
* Minimal duration gap of personal access token update.
|
||||
*/
|
||||
private static final Duration MIN_UPDATE_GAP = Duration.ofMinutes(1);
|
||||
|
||||
private final ReactiveAuthenticationManager delegate;
|
||||
private final JwtReactiveAuthenticationManager delegate;
|
||||
|
||||
private final ReactiveExtensionClient client;
|
||||
|
||||
|
@ -52,33 +49,28 @@ public class PatAuthenticationManager implements ReactiveAuthenticationManager {
|
|||
this.clock = Clock.systemDefaultZone();
|
||||
}
|
||||
|
||||
private ReactiveAuthenticationManager getDelegate() {
|
||||
private JwtReactiveAuthenticationManager getDelegate() {
|
||||
var jwtDecoder = withJwkSource(signedJWT -> Flux.just(cryptoService.getJwk()))
|
||||
.build();
|
||||
return new JwtReactiveAuthenticationManager(jwtDecoder);
|
||||
}
|
||||
|
||||
public void setClock(Clock clock) {
|
||||
/**
|
||||
* Set new clock. Only for testing.
|
||||
*
|
||||
* @param clock new clock
|
||||
*/
|
||||
void setClock(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Authentication authentication) {
|
||||
return Mono.just(authentication)
|
||||
.map(this::clearPrefix)
|
||||
.flatMap(delegate::authenticate)
|
||||
return delegate.authenticate(authentication)
|
||||
.cast(JwtAuthenticationToken.class)
|
||||
.flatMap(this::checkAndRebuild);
|
||||
}
|
||||
|
||||
private Authentication clearPrefix(Authentication authentication) {
|
||||
if (authentication instanceof BearerTokenAuthenticationToken bearerToken) {
|
||||
var newToken = removeStart(bearerToken.getToken(), PAT_TOKEN_PREFIX);
|
||||
return new BearerTokenAuthenticationToken(newToken);
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
|
||||
private Mono<JwtAuthenticationToken> checkAndRebuild(JwtAuthenticationToken jat) {
|
||||
var jwt = jat.getToken();
|
||||
var patName = jwt.getClaimAsString("pat_name");
|
||||
|
|
|
@ -15,7 +15,7 @@ import run.halo.app.extension.GroupVersion;
|
|||
import run.halo.app.security.PersonalAccessToken;
|
||||
|
||||
@Component
|
||||
public class PatEndpoint implements CustomEndpoint {
|
||||
class PatEndpoint implements CustomEndpoint {
|
||||
|
||||
private final UserScopedPatHandler patHandler;
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package run.halo.app.security.authentication.pat;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.oauth2.server.resource.web.server.BearerTokenServerAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
|
||||
import org.springframework.security.web.server.authentication.ServerAuthenticationEntryPointFailureHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
import run.halo.app.security.authentication.CryptoService;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
/**
|
||||
* PAT security configurer.
|
||||
*
|
||||
* @author johnniang
|
||||
* @since 2.20.4
|
||||
*/
|
||||
@Component
|
||||
// Specific an order here to control the order or security configurer initialization
|
||||
@Order(0)
|
||||
class PatSecurityConfigurer implements SecurityConfigurer {
|
||||
|
||||
private final ReactiveExtensionClient client;
|
||||
|
||||
private final CryptoService cryptoService;
|
||||
|
||||
public PatSecurityConfigurer(ReactiveExtensionClient client, CryptoService cryptoService) {
|
||||
this.client = client;
|
||||
this.cryptoService = cryptoService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ServerHttpSecurity http) {
|
||||
var filter =
|
||||
new AuthenticationWebFilter(new PatAuthenticationManager(client, cryptoService));
|
||||
filter.setServerAuthenticationConverter(new PatAuthenticationConverter());
|
||||
var entryPoint = new BearerTokenServerAuthenticationEntryPoint();
|
||||
var failureHandler = new ServerAuthenticationEntryPointFailureHandler(entryPoint);
|
||||
filter.setAuthenticationFailureHandler(failureHandler);
|
||||
http.addFilterAt(filter, SecurityWebFiltersOrder.AUTHENTICATION);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package run.halo.app.security.authentication.pat;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.web.server.authentication.ServerBearerTokenAuthenticationConverter;
|
||||
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class PatServerWebExchangeMatcher implements ServerWebExchangeMatcher {
|
||||
|
||||
public static final String PAT_TOKEN_PREFIX = "pat_";
|
||||
|
||||
private final ServerAuthenticationConverter authConverter =
|
||||
new ServerBearerTokenAuthenticationConverter();
|
||||
|
||||
@Override
|
||||
public Mono<MatchResult> matches(ServerWebExchange exchange) {
|
||||
return authConverter.convert(exchange)
|
||||
.filter(a -> a instanceof BearerTokenAuthenticationToken)
|
||||
.cast(BearerTokenAuthenticationToken.class)
|
||||
.map(BearerTokenAuthenticationToken::getToken)
|
||||
.filter(tokenString -> StringUtils.startsWith(tokenString, PAT_TOKEN_PREFIX))
|
||||
.flatMap(t -> MatchResult.match())
|
||||
.onErrorResume(AuthenticationException.class, t -> MatchResult.notMatch())
|
||||
.switchIfEmpty(Mono.defer(MatchResult::notMatch));
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package run.halo.app.security.authentication.pat.impl;
|
||||
package run.halo.app.security.authentication.pat;
|
||||
|
||||
import static run.halo.app.extension.Comparators.compareCreationTimestamp;
|
||||
import static run.halo.app.security.authentication.pat.PatServerWebExchangeMatcher.PAT_TOKEN_PREFIX;
|
||||
import static run.halo.app.security.authentication.pat.PatAuthenticationConverter.PAT_TOKEN_PREFIX;
|
||||
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||
|
@ -41,11 +41,10 @@ import run.halo.app.infra.exception.AccessDeniedException;
|
|||
import run.halo.app.infra.exception.NotFoundException;
|
||||
import run.halo.app.security.PersonalAccessToken;
|
||||
import run.halo.app.security.authentication.CryptoService;
|
||||
import run.halo.app.security.authentication.pat.UserScopedPatHandler;
|
||||
import run.halo.app.security.authorization.AuthorityUtils;
|
||||
|
||||
@Service
|
||||
public class UserScopedPatHandlerImpl implements UserScopedPatHandler {
|
||||
class UserScopedPatHandlerImpl implements UserScopedPatHandler {
|
||||
|
||||
private static final String ACCESS_TOKEN_ANNO_NAME = "security.halo.run/access-token";
|
||||
|
Loading…
Reference in New Issue