• Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器


    概要

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

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

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

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

    优点

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

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

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

    快速上手

    项目说明

    工程名 端口 作用
    jwt-authserver 8080 授权服务器
    jwt-resourceserver 8081 资源服务器

    授权服务器

    pom.xml

    <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-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth.boot</groupId>
        <artifactId>spring-security-oauth2-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

    @Configuration
    public 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。

    OAuth2AuthorizationServer

    /**
     * 授权服务器
     */
    @Configuration
    @EnableAuthorizationServer
    public class OAuth2AuthorizationServer 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-oauth2-resource-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth.boot</groupId>
        <artifactId>spring-security-oauth2-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;
        }
    
    }
    

    OAuth2ResourceServer

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

    application.yml

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

    参数说明:

    • security.oauth2.resource.jwt.key-value:设置签名key 保持和授权服务器一致。
    • security.oauth2.resource.jwt:项目启动过程中,检查到配置文件中有
      security.oauth2.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-oauth2-jwt




    欢迎扫码或微信搜索公众号《程序员果果》关注我,关注有惊喜~

  • 相关阅读:
    ajax--->简单加法小练习
    Django----->Ajax
    Django----->inclusion_tag的使用
    分页插件
    权限--中间件
    Django----->一周后的重温
    Django---->视图(View)
    【转载】chmod命令详解
    【转载】linux ls -l命令详解
    js自定制周期函数
  • 原文地址:https://www.cnblogs.com/huanchupkblog/p/10657650.html
Copyright © 2020-2023  润新知