ホームページ >Java >&#&チュートリアル >SpringBoot+SpringSecurity+JWT を使用してシステムの認証と認可を実装する方法
Spring Security は Spring のコア プロジェクトであり、強力で高度にカスタマイズ可能な認証およびアクセス制御フレームワークです。これは、認証および認可機能に加えて一般的な攻撃に対する保護を提供し、Spring ベースのアプリケーションを保護するための事実上の標準となっています。
Spring Boot は自動構成を提供しており、スターター依存関係を導入することで使用できます。
Spring Security の機能の概要:
使いやすく、Spring Boot スターターの依存関係を提供し、Spring Boot プロジェクトとの統合が簡単です。
プロフェッショナル。CSRF 保護、クリックジャッキング保護、XSS 保護などを提供し、さまざまなセキュリティ ヘッダー統合 (X-XSS-Protection、X-Frame-Options など) を提供します。
パスワード暗号化ストレージ、複数の暗号化アルゴリズムをサポート
非常にスケーラブルでカスタマイズ可能
OAuth3 JWT認証サポート
この記事では、次のように JDK と Spring Boot バージョンの使用を示していることに注意してください:Spring Boot プロジェクトの pom.xml ファイルに次の依存関係を追加します。Spring Boot: 2.7.2
JDK: 11
Spring Boot のバージョンが異なれば構成も異なりますが、原則は同じです。
<!-- Spring Security的Spring boot starter,引入后将自动启动Spring Security的自动配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- 下面的依赖包含了OAuth3 JWT认证实现 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth3-resource-server</artifactId> </dependency>上記の 2 つの依存関係で十分です。 4. JWT 認証を使用するように Spring Security を構成する
主に SecurityFilterBean を生成するための HttpSecurity Bean の設定を行います。 Spring Boot で実行する プロジェクトの Resource ディレクトリに RSA キーのペアを生成します。注: Spring Boot バージョンが異なれば構成も異なりますが、原理は同じです。スプリングブート: 2.7.2。
次の Web サイトを使用して生成できます: http://tools.jb51.net/password/rsa_encode/,
注: キーの形式は PKCS#8 を使用し、秘密キーのパスワードは空です。もう 1 つ説明する必要があります。コード内で Spring Boot の値インジェクションを使用しました:
import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.source.ImmutableJWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth3.jwt.JwtDecoder; import org.springframework.security.oauth3.jwt.JwtEncoder; import org.springframework.security.oauth3.jwt.NimbusJwtDecoder; import org.springframework.security.oauth3.jwt.NimbusJwtEncoder; import org.springframework.security.oauth3.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth3.server.resource.authentication.JwtGrantedAuthoritiesConverter; import org.springframework.security.oauth3.server.resource.web.BearerTokenAuthenticationEntryPoint; import org.springframework.security.oauth3.server.resource.web.access.BearerTokenAccessDeniedHandler; import org.springframework.security.web.SecurityFilterChain; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; /** * Spring Security 配置 * * @author cloudgyb * @since 2022/7/30 18:31 */ @Configuration(proxyBeanMethods = false) @EnableMethodSecurity public class WebSecurityConfigurer { //使用RSA对JWT做签名,所以这里需要一对秘钥。 //秘钥文件的路径在application.yml文件中做了配置(具体配置在下面)。 @Value("${jwt.public.key}") private RSAPublicKey key; @Value("${jwt.private.key}") private RSAPrivateKey priv; /** * 构建SecurityFilterChain bean */ @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { //"/login"是系统的登录接口,所以需要匿名可访问 http.authorizeRequests().antMatchers("/login").anonymous(); //其他请求都需认证后才能访问 http.authorizeRequests().anyRequest().authenticated() .and() //采用JWT认证无需session保持,所以禁用掉session管理器 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() //login接口可能来自其他站点,所以对login不做csrf防护 .csrf((csrf) -> csrf.ignoringAntMatchers("/login")) //配置认证方式为JWT,并且配置了一个JWT认证装换器,用于去掉解析权限时的SCOOP_前缀 .oauth3ResourceServer().jwt().jwtAuthenticationConverter( JwtAuthenticationConverter() ); //配置认证失败或者无权限时的处理器 http.exceptionHandling((exceptions) -> exceptions .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint()) .accessDeniedHandler(new BearerTokenAccessDeniedHandler()) ); //根据配置生成SecurityFilterChain对象 return http.build(); } /** * JWT解码器,用于认证时的JWT解码 */ @Bean JwtDecoder jwtDecoder() { return NimbusJwtDecoder.withPublicKey(this.key).build(); } /** * JWT编码器,生成JWT */ @Bean JwtEncoder jwtEncoder() { JWK jwk = new RSAKey.Builder(this.key).privateKey(this.priv).build(); JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk)); return new NimbusJwtEncoder(jwks); } /** * JWT认证解码时,去掉Spring Security对权限附带的默认前缀SCOOP_ */ @Bean JwtAuthenticationConverter JwtAuthenticationConverter() { final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); jwtGrantedAuthoritiesConverter.setAuthorityPrefix(""); final JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter); return jwtAuthenticationConverter; } }興味がありますか? Spring Boot とは何ですか? yaml ファイル内の文字列に対応するファイルを RSAPublicKey と RSAPrivateKey に変換するにはどうすればよいですか? 実際には、Spring Security が処理を行ってくれました。Spring Security でコンバータ ResourceKeyConverterAdapter を実装するのに役立ちました。より深い理解のために、関連するソース コードを読むことができます。
これまでのところ、私たちのプロジェクトは JWT 認証をサポートしています。しかし、ユーザーは認証を通過してサーバー リソースにアクセスするには、リクエスト ヘッダーの認可に正規の JWT を含める必要があります。では、ユーザーに正規の JWT を発行するにはどうすればよいでしょうか?
これは非常に簡単で、ログイン インターフェイスを提供し、ユーザーにユーザー名とパスワードを入力させ、照合が成功した後にトークンを発行することができます。実際には、これは必要ありません。他の方法があります。たとえば、サードパーティのインターフェイスを呼び出すとき、通常のアプローチは、最初にサードパーティに適用することです。承認されればトークンを取得できます。このプロセスは上記のログイン後のトークン発行と同じで、どちらも合法的な手段でトークンを取得します。
5. ログイン インターフェイスの実装
ログイン API インターフェイス:jwt: private.key: classpath:app.key public.key: classpath:app.pubログイン ロジックの実装:
@Value("${jwt.public.key}") private RSAPublicKey key; @Value("${jwt.private.key}") private RSAPrivateKey priv;
6. テスト
間違ったパスワードを使用すると、認証が失敗したことを示す 401 Unauthorized ステータス コードが返されます!
正しいユーザー名とパスワードを使用する:JWT トークンが返されました。
この時点で、クライアントは有効なトークンを取得し、サーバー上でアクセスできるリソースにアクセスできるようになります。
テスト インターフェイスを作成しました:@RestController public class SysLoginController { private final SysLoginService sysLoginService; public SysLoginController(SysLoginService sysLoginService) { this.sysLoginService = sysLoginService; } @PostMapping("/login") public String login(@RequestBody LoginInfo loginInfo) { return sysLoginService.login(loginInfo); } }このインターフェイスではユーザーに「テスト」権限が必要ですが、ログインしているユーザーにはこの権限がありません (アプリの権限は 1 つだけです)。インターフェイスは次のように呼ばれます: 最初に、前のログイン手順で取得したトークンをトークンに貼り付けます:
我们发送请求得到了403 Forbidden的响应,意思就是我们没有访问权限,此时我们将接口权限改为“app”:
@RestController public class HelloController { @GetMapping("/") @PreAuthorize("hasAuthority('app')") public String hello(Authentication authentication) { return "Hello, " + authentication.getName() + "!"; } }
重启项目。再次发起请求:
以上がSpringBoot+SpringSecurity+JWT を使用してシステムの認証と認可を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。