概要

之前的两篇文章,讲述了Spring Security 结合 OAuth3 、JWT 的使用,这一节要求对 OAuth3、JWT 有了解,若不清楚,先移步到下面两篇提前了解下。

Spring Boot Security 整合 OAuth3 设计安全API接口服务

Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

这一篇我们来实现 支持 JWT令牌 的授权服务器。

优点

使用 OAuth3 是向认证服务器申请令牌,客户端拿这令牌访问资源服务服务器,资源服务器校验了令牌无误后,如果资源的访问用到用户的相关信息,那么资源服务器还需要根据令牌关联查询用户的信息。

使用 JWT 是客户端通过用户名、密码 请求服务器获取 JWT,服务器判断用户名和密码无误之后,可以将用户信息和权限信息经过加密成 JWT 的形式返回给客户端。在之后的请求中,客户端携带 JWT 请求需要访问的资源,如果资源的访问用到用户的相关信息,那么就直接从JWT中获取到。

所以,如果我们在使用 OAuth3 时结合JWT ,就能节省集中式令牌校验开销,实现无状态授权认证。

快速上手项目说明工程名端口作用jwt-authserver8080授权服务器jwt-resourceserver8081资源服务器授权服务器pom.xml

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth3-resource-server</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth3-client</artifactId></dependency><dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth3-autoconfigure</artifactId> <version>2.1.3.RELEASE</version></dependency><dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>1.0.10.RELEASE</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>WebSecurityConfig

@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http. authorizeRequests().antMatchers("/**").permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("123456").roles("USER"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new PasswordEncoder() { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return Objects.equals(charSequence.toString(),s); } }; }}

为了方便,使用内存模式,在内存中创建一个用户 user 密码 123456。

OAuth3AuthorizationServer

/** * 授权服务器 */@Configuration@EnableAuthorizationServerpublic class OAuth3AuthorizationServer extends AuthorizationServerConfigurerAdapter { /** * 注入AuthenticationManager ,密码模式用到 */ @Autowired private AuthenticationManager authenticationManager; /** * 对Jwt签名时,增加一个密钥 * JwtAccessTokenConverter:对Jwt来进行编码以及解码的类 */ @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("test-secret"); return converter; } /** * 设置token 由Jwt产生,不使用默认的透明令牌 */ @Bean public JwtTokenStore jwtTokenStore() { return new JwtTokenStore(accessTokenConverter()); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .authenticationManager(authenticationManager) .tokenStore(jwtTokenStore()) .accessTokenConverter(accessTokenConverter()); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("clientapp") .secret("123") .scopes("read") //设置支持[密码模式、授权码模式、token刷新] .authorizedGrantTypes( "password", "authorization_code", "refresh_token"); }}资源服务器pom.xml

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth3-resource-server</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth3-client</artifactId></dependency><dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth3-autoconfigure</artifactId> <version>2.1.3.RELEASE</version></dependency><dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>1.0.10.RELEASE</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>HelloController

@RestController("/api")public class HelloController { @PostMapping("/api/hi") public String say(String name) { return "hi , " + name; }}OAuth3ResourceServer

/** * 资源服务器 */@Configuration@EnableResourceServerpublic class OAuth3ResourceServer extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated().and() .requestMatchers().antMatchers("/api/**"); }}application.yml

server: port: 8081security: oauth3: resource: jwt: key-value: test-secret

参数说明:

security.oauth3.resource.jwt.key-value:设置签名key 保持和授权服务器一致。security.oauth3.resource.jwt:项目启动过程中,检查到配置文件中有
security.oauth3.resource.jwt 的配置,就会生成 jwtTokenStore 的 bean,对令牌的校验就会使用 jwtTokenStore 。验证

请求令牌

curl -X POST --user 'clientapp:123' -d 'grant_type=password&username=user&password=123456' http://localhost:8080/oauth/token

返回JWT令牌

{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ0MzExMDgsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGM0YWMyOTYtMDQwYS00Y2UzLTg5MTAtMWJmNjZkYTQwOTk3IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIiwic2NvcGUiOlsicmVhZCJdfQ.YAaSRN0iftmlR6Khz9UxNNEpHHn8zhZwlQrCUCPUmsU", "token_type": "bearer", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicmVhZCJdLCJhdGkiOiI4YzRhYzI5Ni0wNDBhLTRjZTMtODkxMC0xYmY2NmRhNDA5OTciLCJleHAiOjE1NTY5Nzk5MDgsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiI0ZjA5M2ZjYS04NmM0LTQxZWUtODcxZS1kZTY2ZjFhOTI0NTAiLCJjbGllbnRfaWQiOiJjbGllbnRhcHAifQ.vvAE2LcqggBv8pxuqU6RKPX65bl7Zl9dfcoIbIQBLf4", "expires_in": 43199, "scope": "read", "jti": "8c4ac296-040a-4ce3-8910-1bf66da40997"}

携带JWT令牌请求资源

curl -X POST -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ0MzExMDgsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGM0YWMyOTYtMDQwYS00Y2UzLTg5MTAtMWJmNjZkYTQwOTk3IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIiwic2NvcGUiOlsicmVhZCJdfQ.YAaSRN0iftmlR6Khz9UxNNEpHHn8zhZwlQrCUCPUmsU" -d 'name=zhangsan' http://localhost:8081/api/hi

返回

hi , zhangsan源码

https://github.com/gf-huanchupk/SpringBootLearning/tree/master/springboot-security-oauth3-jwt

欢迎关注我的公众号《程序员果果》,关注有惊喜~~