• 使用 spring-security-oauth2 体验 OAuth 2.0 的四种授权模式


    背景

    一直对OAuth 2.0的四种授权模式比较好奇,了解的仅限网上的资料,没有使用代码体验过,这次使用spring-security-oauth2来体验这四种模式的整个过程。

    相关代码

    pom文件
    
    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
                <version>2.1.4.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.1.4.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.security.oauth</groupId>
                <artifactId>spring-security-oauth2</artifactId>
                <version>2.0.16.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <artifactId>spring-core</artifactId>
                        <groupId>org.springframework</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>spring-context</artifactId>
                        <groupId>org.springframework</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>spring-beans</artifactId>
                        <groupId>org.springframework</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>spring-security-core</artifactId>
                        <groupId>org.springframework.security</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>26.0-jre</version>
            </dependency>
        </dependencies>
    
    折叠
    配置类
    
    @Configuration
    @EnableAuthorizationServer
    public class MyAuthorizationServerConfigurerAdapter extends AuthorizationServerConfigurerAdapter {
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients
                    .inMemory()
                    .withClient("clientUser")
                    .secret("{bcrypt}" + new BCryptPasswordEncoder().encode("123456"))
                    .authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials");
        }
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
            DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
            UserDetails userDetails = User.withUsername("username")
                    .password("{bcrypt}" + new BCryptPasswordEncoder().encode("password"))
                    .roles("123")
                    .build();
            InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(userDetails);
            daoAuthenticationProvider.setUserDetailsService(inMemoryUserDetailsManager);
            AuthenticationManager authenticationManager = new ProviderManager(
                    Lists.<AuthenticationProvider>newArrayList(daoAuthenticationProvider));
            endpoints.authenticationManager(authenticationManager);
        }
    }
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Bean
        public InMemoryUserDetailsManager inMemoryUserDetailsManager(
                SecurityProperties properties) {
            SecurityProperties.User user = properties.getUser();
            List<String> roles = user.getRoles();
            return new InMemoryUserDetailsManager(User.withUsername("user")
                    .password("{bcrypt}" + new BCryptPasswordEncoder().encode("123456"))
                    .roles(StringUtils.toStringArray(roles)).build());
        }
    }
    
    折叠
    启动类
    
    @SpringBootApplication(
            exclude = UserDetailsServiceAutoConfiguration.class
            // excludeName = "org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration"
    )
    public class SpringSecurityStudyApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecurityStudyApplication.class, args);
        }
    }
    

    授权码模式

    第一步 访问GET /oauth/authorize

    相关代码在org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint
    org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint

    请求参数和返回结果如下:

    返回结果在浏览器上展示的话,是让用户来勾选是否同意授权的一个页面,还有返回结果的_csrf的值要作为第二步的参数。

    curl如下:

    curl --location --request GET 'http://127.0.0.1:8090/oauth/authorize?response_type=code&client_id=clientUser&redirect_uri=https://www.baidu.com/&scope=scope' \
    --header 'Authorization: Basic dXNlcjoxMjM0NTY=' \
    --header 'Cookie: JSESSIONID=AB254815273DB81F1F3BAF74E94DAAB6'
    

    第二步 访问POST /oauth/authorize

    相关代码在org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint

    crul如下:

    curl --location --request POST 'http://127.0.0.1:8090/oauth/authorize?user_oauth_approval=true&scope.scope=true&_csrf=a95516db-6ce2-4033-9b81-1060b6c4d829' \
    --header 'Cookie: JSESSIONID=73E846796ACB7818E09B93AC4CFD320D'
    

    _csrf 要使用第一步返回的结果,在返回头的Location里可以得到授权码

    第一个参数必须要有,因为:

    <input name="user_oauth_approval" value="true" type="hidden"/>
    
    @RequestMapping(value = "/oauth/authorize", method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL)
    public View approveOrDeny(@RequestParam Map<String, String> approvalParameters, Map<String, ?> model, SessionStatus sessionStatus, Principal principal) {
    }
    
    public static final String USER_OAUTH_APPROVAL = "user_oauth_approval";
    

    第二个参数是用户是否同意授权

    第三步 访问POST /oauth/token

    相关代码在org.springframework.security.oauth2.provider.endpoint.TokenEndpoint

    code 使用第二步的返回结果

    crul如下:

    curl --location --request POST 'http://127.0.0.1:8090/oauth/token' \
    --header 'Authorization: Basic Y2xpZW50VXNlcjoxMjM0NTY=' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --header 'Cookie: JSESSIONID=5D41BF01BC875BDF266D3C2178537F21' \
    --data-urlencode 'grant_type=authorization_code' \
    --data-urlencode 'code=1pakV1' \
    --data-urlencode 'redirect_uri=https://www.baidu.com/' \
    --data-urlencode 'client_id=clientUser' \
    --data-urlencode 'scope=scope'
    

    简化模式

    第一步 访问GET /oauth/authorize

    crul如下:

    curl --location --request GET 'http://127.0.0.1:8090/oauth/authorize?response_type=token&client_id=clientUser&redirect_uri=https://www.baidu.com/&scope=scope' \
    --header 'Authorization: Basic dXNlcjoxMjM0NTY=' \
    --header 'Cookie: JSESSIONID=6AD429F6CF30C10C0E9F1A35EC78A790'
    

    第二步 访问POST /oauth/authorize


    crul如下:

    curl --location --request POST 'http://127.0.0.1:8090/oauth/authorize?user_oauth_approval=true&scope.scope=true&_csrf=1ba6be5e-845f-47f2-9680-db613adc47c7' \
    --header 'Cookie: JSESSIONID=6AD429F6CF30C10C0E9F1A35EC78A790'
    

    密码模式

    直接访问POST /oauth/token

    curl如下:

    curl --location --request POST 'http://127.0.0.1:8090/oauth/token' \
    --header 'Authorization: Basic Y2xpZW50VXNlcjoxMjM0NTY=' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --header 'Cookie: JSESSIONID=7E149951AB7D3C03E31E21450754DAAE' \
    --data-urlencode 'grant_type=password' \
    --data-urlencode 'username=username' \
    --data-urlencode 'scope=scope' \
    --data-urlencode 'password=password'
    

    客户端模式

    直接访问POST /oauth/token

    curl如下:

    curl --location --request POST 'http://127.0.0.1:8090/oauth/token' \
    --header 'Authorization: Basic Y2xpZW50VXNlcjoxMjM0NTY=' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --header 'Cookie: JSESSIONID=7E149951AB7D3C03E31E21450754DAAE' \
    --data-urlencode 'grant_type=client_credentials' \
    --data-urlencode 'scope=scope'
    

    参考

    理解OAuth 2.0 - 阮一峰

  • 相关阅读:
    交换两个数字(字符) 学习随笔
    java面试题整理《微服务篇》六
    数据结构——排序
    每日一文(第一天)
    【《C Primer Plus》读书笔记】第7章:C控制语句:分支和跳转
    基于SpringBoot和Vue的厨到家服务平台的设计与实现毕业设计源码063133
    Autoxjs 实践-Spring Boot 集成 WebSocket
    LLM——langchain 与阿里 DashScop (通义千问大模型) 和 DashVector(向量数据库) 结合使用总结
    DELAY_APPLY 配置参数
    【前端】npm常用命令
  • 原文地址:https://www.cnblogs.com/eaglelihh/p/16463706.html