15.1 Using tokens signed with symmetric keys with JWT

一个token由三个部分组成:

  • header
  • body
  • signature

image.png

15.1.2 Implementing an authorization server to issue JWTs

对称秘钥的图示:
image.png
导入依赖:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-web</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>org.springframework.cloud</groupId>
  11. <artifactId>spring-cloud-starter-oauth2</artifactId>
  12. </dependency>

配置JwtTokenStore

  1. @Configuration
  2. @EnableAuthorizationServer
  3. public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
  4. @Value("${jwt.key}")
  5. private String jwtKey;
  6. @Autowired
  7. private AuthenticationManager authenticationManager;
  8. @Override
  9. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  10. clients.inMemory()
  11. .withClient("client")
  12. .secret("secret")
  13. .authorizedGrantTypes("password", "refresh_token")
  14. .scopes("read");
  15. }
  16. @Override
  17. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  18. endpoints.authenticationManager(authenticationManager)
  19. .tokenStore(tokenStore())
  20. .accessTokenConverter(jwtAccessTokenConverter());
  21. }
  22. private JwtAccessTokenConverter jwtAccessTokenConverter() {
  23. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  24. converter.setSigningKey(jwtKey);
  25. return converter;
  26. }
  27. private TokenStore tokenStore() {
  28. return new JwtTokenStore(jwtAccessTokenConverter());
  29. }
  30. }

配置用户管理

  1. @Configuration
  2. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Bean
  4. public UserDetailsService uds() {
  5. InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager();
  6. UserDetails u = User.withUsername("john")
  7. .password("12345")
  8. .authorities("read")
  9. .build();
  10. uds.createUser(u);
  11. return uds;
  12. }
  13. @Bean
  14. public PasswordEncoder passwordEncoder(){
  15. return NoOpPasswordEncoder.getInstance();
  16. }
  17. @Bean
  18. public AuthenticationManager authenticationManagerBean() throws Exception {
  19. return super.authenticationManagerBean();
  20. }
  21. }

对称秘钥:
image.png
启动项目:
image.png
image.png

15.1.3 Implementing a resource server that uses JWT

导入依赖:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-web</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>org.springframework.cloud</groupId>
  11. <artifactId>spring-cloud-starter-oauth2</artifactId>
  12. </dependency>

添加一个端点:

  1. @RestController
  2. public class HelloController {
  3. @GetMapping("/hello")
  4. public String hello() {
  5. return "Hello World!";
  6. }
  7. }

资源服务的配置类

  1. @Configuration
  2. @EnableResourceServer
  3. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  4. @Value("${jwt.key}")
  5. private String jwtKey;
  6. @Override
  7. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  8. resources.tokenStore(tokenStore());
  9. }
  10. @Bean
  11. public TokenStore tokenStore() {
  12. return new JwtTokenStore(jwtAccessTokenConverter());
  13. }
  14. @Bean
  15. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  16. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  17. converter.setSigningKey(jwtKey);
  18. return converter;
  19. }
  20. }

启动项目并测试:
image.png

15.2 Using tokens signed with asymmetric keys with JWT

15.2.1 Generating the key pair

生成一个private key
image.png
下载OpenSSL并配置环境变量
运行命令:
image.png

  1. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlm7kFtp0Wy5aDFza3pC
  2. skdogef8HBVYgyPZxE4CSmtdgyvYzNMmIiAbz18QJgZJwg4bxEKf1GrRzk3ZVVfV
  3. njw1lHlO23wHX/dZrHNPqFbj6WTbpcfksqq+8ue2bczoiTlB9L+ATghwGwJMelDV
  4. yUGTWyLZMZBxTtywC17ZUtMExbEJkhc3kMfRVf5YUzU0SrreFiHZcKnFce4vtRtZ
  5. 9qwjljN1ZlwEbA849758JjFiKSBWe2U2ZqvH8uVZflJ4wU+czCGgRYrCIh89/lMm
  6. ZNtO7Ct7FwAGFzCB4d9YSRHtikIez8XYTGiORC5+o9FvO25tUsxI7R8MmBWzmmVr
  7. UwIDAQAB
  8. -----BEGIN PUBLIC KEY
  9. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlm7kFtp0Wy5aDFza3pC
  10. skdogef8HBVYgyPZxE4CSmtdgyvYzNMmIiAbz18QJgZJwg4bxEKf1GrRzk3ZVVfV
  11. njw1lHlO23wHX/dZrHNPqFbj6WTbpcfksqq+8ue2bczoiTlB9L+ATghwGwJMelDV
  12. yUGTWyLZMZBxTtywC17ZUtMExbEJkhc3kMfRVf5YUzU0SrreFiHZcKnFce4vtRtZ
  13. 9qwjljN1ZlwEbA849758JjFiKSBWe2U2ZqvH8uVZflJ4wU+czCGgRYrCIh89/lMm
  14. ZNtO7Ct7FwAGFzCB4d9YSRHtikIez8XYTGiORC5+o9FvO25tUsxI7R8MmBWzmmVr
  15. UwIDAQAB
  16. -----END PUBLIC KEY-----

15.2.2 Implementing an authorization server that uses private keys

image.png
配置文件:

  1. password=ssia123
  2. privateKey=ssia.jks
  3. alias=ssia

授权服务的配置类:

  1. /**
  2. * Created by ql on 2022/5/26
  3. */
  4. @Configuration
  5. @EnableAuthorizationServer
  6. public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
  7. @Value("${password}")
  8. private String password;
  9. @Value("${privateKey}")
  10. private String privateKey;
  11. @Value("${alias}")
  12. private String alias;
  13. @Autowired
  14. private AuthenticationManager authenticationManager;
  15. @Override
  16. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  17. clients.inMemory()
  18. .withClient("client")
  19. .secret("secret")
  20. .authorizedGrantTypes("password", "refresh_token")
  21. .scopes("read");
  22. }
  23. @Override
  24. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  25. endpoints.authenticationManager(authenticationManager)
  26. .tokenStore(tokenStore())
  27. .accessTokenConverter(jwtAccessTokenConverter());
  28. }
  29. private JwtAccessTokenConverter jwtAccessTokenConverter() {
  30. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  31. KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(privateKey), password.toCharArray());
  32. converter.setKeyPair(keyStoreKeyFactory.getKeyPair(alias));
  33. return converter;
  34. }
  35. private TokenStore tokenStore() {
  36. return new JwtTokenStore(jwtAccessTokenConverter());
  37. }
  38. }

15.2.3 Implementing a resource server that uses public keys

image.png
配置文件:

  1. server.port=9090
  2. publicKey=-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlm7kFtp0Wy5aDFza3pCskdogef8HBVYgyPZxE4CSmtdgyvYzNMmIiAbz18QJgZJwg4bxEKf1GrRzk3ZVVfVnjw1lHlO23wHX/dZrHNPqFbj6WTbpcfksqq+8ue2bczoiTlB9L+ATghwGwJMelDVyUGTWyLZMZBxTtywC17ZUtMExbEJkhc3kMfRVf5YUzU0SrreFiHZcKnFce4vtRtZ9qwjljN1ZlwEbA849758JjFiKSBWe2U2ZqvH8uVZflJ4wU+czCGgRYrCIh89/lMmZNtO7Ct7FwAGFzCB4d9YSRHtikIez8XYTGiORC5+o9FvO25tUsxI7R8MmBWzmmVrUwIDAQAB-----END PUBLIC KEY-----

15.2.4 Using an endpoint to expose the public key

在授权服务中添加:
image.png
还得添加这段,不然后面会报错
image.png
启动项目并访问:curl -u resourceserver:resourceserversecret http://localhost:8080/oauth/token_key
image.png
修改资源服务的配置

  1. server.port=9090
  2. security.oauth2.resource.jwt.key-uri=http://localhost:8080/oauth/token_key
  3. security.oauth2.client.client-id=resourceserver
  4. security.oauth2.client.client-secret=resourceserversecret

修改资源服务的配置为空:

  1. @Configuration
  2. @EnableResourceServer
  3. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  4. }

15.3 Adding custom details to the JWT

15.3.1 Configuring the authorization server to add custom details to tokens

这部分跳过了,今天学Spring Security太久了,有点疲了