[英]How to implement JWT based authentication and authorization in Spring Security
[英]Spring Security filters for JWT-based authentication, verification and authorization scheme, by example
Java + Spring(和 Spring Security)在這里,有興趣使用承載令牌為我的 Web 服務實現基於 JWT 的身份驗證機制。 我對使用 Spring Security 進行身份驗證和授權的正確方法的理解是通過使用提供的(或自定義的)過濾器,如下所示:
WebSecurityConfigurerAdapter
的@EnableWebSecurity
Web 安全類中WebSecurityConfigurerAdapter
因此,首先,如果我上面所說的任何內容是 Spring Security(或一般的 Web 安全)反模式或被誤導,請首先提供課程更正並引導我朝着正確的方向前進!
假設我或多或少正確理解了上面的“身份驗證流程”......
是否有任何特定的 Spring Security 過濾器已經為我處理了所有這些問題,或者可以擴展並覆蓋一些方法來以這種方式運行? 或者任何非常接近的東西? 查看特定於身份驗證的 Spring Security 過濾器列表,我看到:
UsernamePasswordAuthenticationFilter
-> 看起來像是 authn 過濾器的一個不錯的候選者,但在查詢字符串中需要一個username
和password
參數,這對我來說很奇怪,最重要的是,它不會生成 JWTCasAuthenticationFilter
-> 看起來像是用於基於 CAS 的 SSO,不適合在非 SSO 上下文中使用BasicAuthenticationFilter
-> 用於基於 HTTP 基本身份驗證的身份驗證,不適用於更復雜的設置至於令牌驗證和授權,我(出乎我的意料)在 Spring Security 環境中看不到任何符合條件的內容。
除非有人知道我可以輕松使用或子類化的特定於 JWT 的過濾器,否則我認為我需要實現自己的自定義過濾器,在這種情況下,我想知道如何配置 Spring Security 以使用它們而不使用任何其他身份驗證過濾器(例如UsernamePasswordAuthenticationFilter
)作為過濾器鏈的一部分。
據我了解,您想要:
username/password -> JWT
本身並不是一種既定的身份驗證機制,這就是 Spring Security 還沒有直接支持的原因。
不過,您可以很容易地自行獲取它。
首先,創建一個生成 JWT 的/token
端點:
@RestController
public class TokenController {
@Value("${jwt.private.key}")
RSAPrivateKey key;
@PostMapping("/token")
public String token(Authentication authentication) {
Instant now = Instant.now();
long expiry = 36000L;
// @formatter:off
String scope = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
JWTClaimsSet claims = new JWTClaimsSet.Builder()
.issuer("self")
.issueTime(new Date(now.toEpochMilli()))
.expirationTime(new Date(now.plusSeconds(expiry).toEpochMilli()))
.subject(authentication.getName())
.claim("scope", scope)
.build();
// @formatter:on
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).build();
SignedJWT jwt = new SignedJWT(header, claims);
return sign(jwt).serialize();
}
SignedJWT sign(SignedJWT jwt) {
try {
jwt.sign(new RSASSASigner(this.key));
return jwt;
}
catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
}
}
其次,配置 Spring Security 以允許 HTTP Basic(對於/token
端點)和 JWT(對於其余部分):
@Configuration
public class RestConfig extends WebSecurityConfigurerAdapter {
@Value("${jwt.public.key}")
RSAPublicKey key;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests((authz) -> authz.anyRequest().authenticated())
.csrf((csrf) -> csrf.ignoringAntMatchers("/token"))
.httpBasic(Customizer.withDefaults())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.sessionManagement((session) -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler())
);
// @formatter:on
}
@Bean
UserDetailsService users() {
// @formatter:off
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password("{noop}password")
.authorities("app")
.build());
// @formatter:on
}
@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(this.key).build();
}
}
我認為有興趣在spring-authorization-server
添加對此類內容的支持以減少/token
樣板,如果您有興趣貢獻您的努力!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.