15.1 Using tokens signed with symmetric keys with JWT
一个token由三个部分组成:
- header
- body
- signature
15.1.2 Implementing an authorization server to issue JWTs
对称秘钥的图示:
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
配置JwtTokenStore
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${jwt.key}")
private String jwtKey;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(jwtAccessTokenConverter());
}
private JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(jwtKey);
return converter;
}
private TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
}
配置用户管理
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService uds() {
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager();
UserDetails u = User.withUsername("john")
.password("12345")
.authorities("read")
.build();
uds.createUser(u);
return uds;
}
@Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
15.1.3 Implementing a resource server that uses JWT
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
添加一个端点:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}
}
资源服务的配置类
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Value("${jwt.key}")
private String jwtKey;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(jwtKey);
return converter;
}
}
15.2 Using tokens signed with asymmetric keys with JWT
15.2.1 Generating the key pair
生成一个private key
下载OpenSSL并配置环境变量
运行命令:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlm7kFtp0Wy5aDFza3pC
skdogef8HBVYgyPZxE4CSmtdgyvYzNMmIiAbz18QJgZJwg4bxEKf1GrRzk3ZVVfV
njw1lHlO23wHX/dZrHNPqFbj6WTbpcfksqq+8ue2bczoiTlB9L+ATghwGwJMelDV
yUGTWyLZMZBxTtywC17ZUtMExbEJkhc3kMfRVf5YUzU0SrreFiHZcKnFce4vtRtZ
9qwjljN1ZlwEbA849758JjFiKSBWe2U2ZqvH8uVZflJ4wU+czCGgRYrCIh89/lMm
ZNtO7Ct7FwAGFzCB4d9YSRHtikIez8XYTGiORC5+o9FvO25tUsxI7R8MmBWzmmVr
UwIDAQAB
-----BEGIN PUBLIC KEY
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlm7kFtp0Wy5aDFza3pC
skdogef8HBVYgyPZxE4CSmtdgyvYzNMmIiAbz18QJgZJwg4bxEKf1GrRzk3ZVVfV
njw1lHlO23wHX/dZrHNPqFbj6WTbpcfksqq+8ue2bczoiTlB9L+ATghwGwJMelDV
yUGTWyLZMZBxTtywC17ZUtMExbEJkhc3kMfRVf5YUzU0SrreFiHZcKnFce4vtRtZ
9qwjljN1ZlwEbA849758JjFiKSBWe2U2ZqvH8uVZflJ4wU+czCGgRYrCIh89/lMm
ZNtO7Ct7FwAGFzCB4d9YSRHtikIez8XYTGiORC5+o9FvO25tUsxI7R8MmBWzmmVr
UwIDAQAB
-----END PUBLIC KEY-----
15.2.2 Implementing an authorization server that uses private keys
配置文件:
password=ssia123
privateKey=ssia.jks
alias=ssia
授权服务的配置类:
/**
* Created by ql on 2022/5/26
*/
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${password}")
private String password;
@Value("${privateKey}")
private String privateKey;
@Value("${alias}")
private String alias;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(jwtAccessTokenConverter());
}
private JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(privateKey), password.toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(alias));
return converter;
}
private TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
}
15.2.3 Implementing a resource server that uses public keys
配置文件:
server.port=9090
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
在授权服务中添加:
还得添加这段,不然后面会报错
启动项目并访问:curl -u resourceserver:resourceserversecret http://localhost:8080/oauth/token_key
修改资源服务的配置
server.port=9090
security.oauth2.resource.jwt.key-uri=http://localhost:8080/oauth/token_key
security.oauth2.client.client-id=resourceserver
security.oauth2.client.client-secret=resourceserversecret
修改资源服务的配置为空:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
}
15.3 Adding custom details to the JWT
15.3.1 Configuring the authorization server to add custom details to tokens
这部分跳过了,今天学Spring Security太久了,有点疲了