OAuth 2.0 授权码请求

Posted cjsblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OAuth 2.0 授权码请求相关的知识,希望对你有一定的参考价值。

关于OAuth 2.0,请参见下面这两篇文章(墙裂推荐):

OAuth 2.0

Spring Security OAuth 2.0


 

纸上得来终觉浅,绝知此事要躬行。理论知识了解以后,最终还是要动手实践,不亲自做一遍永远不知道里面有多少坑。本节的重点是用Spring Security实现授权码模式。

1. maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cjs.example</groupId>
    <artifactId>cjs-oauth2-code-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>cjs-oauth2-code-server</name>
    <description></description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

2. 配置Security

package com.cjs.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
//        auth.inMemoryAuthentication().withUser("zhangsan").password("$2a$10$qsJ/Oy1RmUxFA.YtDT8RJ.Y2kU3U4z0jvd35YmiMOAPpD.nZUIRMC").roles("USER");

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
    }


    @Bean
    @Override
    protected UserDetailsService userDetailsService() {
        User.UserBuilder builder = User.builder();
        UserDetails user = builder.username("zhangsan").password("$2a$10$GStfEJEyoSHiSxnoP3SbD.R8XRowP1QKOdi.N6/iFEwEJWTQqlSba").roles("USER").build();
        UserDetails admin = builder.username("lisi").password("$2a$10$GStfEJEyoSHiSxnoP3SbD.R8XRowP1QKOdi.N6/iFEwEJWTQqlSba").roles("USER", "ADMIN").build();
        return new InMemoryUserDetailsManager(user, admin);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        System.out.println(bCryptPasswordEncoder.encode("123456"));
        System.out.println(bCryptPasswordEncoder.encode("12345678"));
    }
}

3. 配置授权服务器

package com.cjs.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;


@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        super.configure(security);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("my-client-1")
                .secret("$2a$10$0jyHr4rGRdQw.X9mrLkVROdQI8.qnWJ1Sl8ly.yzK0bp06aaAkL9W")
                .authorizedGrantTypes("authorization_code", "refresh_token")
                .scopes("all")
                .redirectUris("http://www.baidu.com");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        super.configure(endpoints);
    }

    public static void main(String[] args) {
        System.out.println(new org.apache.tomcat.util.codec.binary.Base64().encodeAsString("my-client-1:12345678".getBytes()));
    }
}

这里客户端的secret是12345678,存储的是加密后的值

4. 启动类

package com.cjs.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CjsOauth2CodeServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(CjsOauth2CodeServerApplication.class, args);
    }
}

到目前为止,好像我们就做了两件事情:一、配置用户;二、注册客户端

现在,我们有两个用户(zhangsan和lisi)以及一个已注册的客户端(my-client-1)

接下来,用postman模拟客户端请求获取access_token

5. 协议端点

我们知道,在获取access_token之前需要用户授权,然后返回一个code,最后用code换access_token

在这个过程中涉及到三个服务器端点:授权端点、重定向端点、令牌端点

通过控制台看看启动日志可能会加深理解:

"C:Program FilesJavajdk1.8.0_152injava" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=50329 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=localhost -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2017.3.4libidea_rt.jar=50331:C:Program FilesJetBrainsIntelliJ IDEA 2017.3.4in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_152jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_152jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_152jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_152jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_152jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_152jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_152jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_152jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_152jrelibext
ashorn.jar;C:Program FilesJavajdk1.8.0_152jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_152jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_152jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_152jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_152jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_152jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_152jrelibjce.jar;C:Program FilesJavajdk1.8.0_152jrelibjfr.jar;C:Program FilesJavajdk1.8.0_152jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_152jrelibjsse.jar;C:Program FilesJavajdk1.8.0_152jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_152jrelibplugin.jar;C:Program FilesJavajdk1.8.0_152jrelib
esources.jar;C:Program FilesJavajdk1.8.0_152jrelib
t.jar;E:cjsworkspacecjs-oauth2-examplecjs-oauth2-code-server	argetclasses;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter-security2.0.3.RELEASEspring-boot-starter-security-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter2.0.3.RELEASEspring-boot-starter-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot2.0.3.RELEASEspring-boot-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-autoconfigure2.0.3.RELEASEspring-boot-autoconfigure-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter-logging2.0.3.RELEASEspring-boot-starter-logging-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositorychqoslogbacklogback-classic1.2.3logback-classic-1.2.3.jar;C:UsersAdministrator.m2
epositorychqoslogbacklogback-core1.2.3logback-core-1.2.3.jar;C:UsersAdministrator.m2
epositoryorgapachelogginglog4jlog4j-to-slf4j2.10.0log4j-to-slf4j-2.10.0.jar;C:UsersAdministrator.m2
epositoryorgapachelogginglog4jlog4j-api2.10.0log4j-api-2.10.0.jar;C:UsersAdministrator.m2
epositoryorgslf4jjul-to-slf4j1.7.25jul-to-slf4j-1.7.25.jar;C:UsersAdministrator.m2
epositoryjavaxannotationjavax.annotation-api1.3.2javax.annotation-api-1.3.2.jar;C:UsersAdministrator.m2
epositoryorgyamlsnakeyaml1.19snakeyaml-1.19.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-aop5.0.7.RELEASEspring-aop-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworksecurityspring-security-config5.0.6.RELEASEspring-security-config-5.0.6.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworksecurityspring-security-web5.0.6.RELEASEspring-security-web-5.0.6.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-expression5.0.7.RELEASEspring-expression-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter-thymeleaf2.0.3.RELEASEspring-boot-starter-thymeleaf-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorg	hymeleaf	hymeleaf-spring53.0.9.RELEASE	hymeleaf-spring5-3.0.9.RELEASE.jar;C:UsersAdministrator.m2
epositoryorg	hymeleaf	hymeleaf3.0.9.RELEASE	hymeleaf-3.0.9.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgattoparserattoparser2.0.4.RELEASEattoparser-2.0.4.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgunbescapeunbescape1.1.5.RELEASEunbescape-1.1.5.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:UsersAdministrator.m2
epositoryorg	hymeleafextras	hymeleaf-extras-java8time3.0.1.RELEASE	hymeleaf-extras-java8time-3.0.1.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter-web2.0.3.RELEASEspring-boot-starter-web-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter-json2.0.3.RELEASEspring-boot-starter-json-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositorycomfasterxmljacksoncorejackson-databind2.9.6jackson-databind-2.9.6.jar;C:UsersAdministrator.m2
epositorycomfasterxmljacksoncorejackson-annotations2.9.0jackson-annotations-2.9.0.jar;C:UsersAdministrator.m2
epositorycomfasterxmljacksoncorejackson-core2.9.6jackson-core-2.9.6.jar;C:UsersAdministrator.m2
epositorycomfasterxmljacksondatatypejackson-datatype-jdk82.9.6jackson-datatype-jdk8-2.9.6.jar;C:UsersAdministrator.m2
epositorycomfasterxmljacksondatatypejackson-datatype-jsr3102.9.6jackson-datatype-jsr310-2.9.6.jar;C:UsersAdministrator.m2
epositorycomfasterxmljacksonmodulejackson-module-parameter-names2.9.6jackson-module-parameter-names-2.9.6.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkootspring-boot-starter-tomcat2.0.3.RELEASEspring-boot-starter-tomcat-2.0.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgapache	omcatembed	omcat-embed-core8.5.31	omcat-embed-core-8.5.31.jar;C:UsersAdministrator.m2
epositoryorgapache	omcatembed	omcat-embed-el8.5.31	omcat-embed-el-8.5.31.jar;C:UsersAdministrator.m2
epositoryorgapache	omcatembed	omcat-embed-websocket8.5.31	omcat-embed-websocket-8.5.31.jar;C:UsersAdministrator.m2
epositoryorghibernatevalidatorhibernate-validator6.0.10.Finalhibernate-validator-6.0.10.Final.jar;C:UsersAdministrator.m2
epositoryjavaxvalidationvalidation-api2.0.1.Finalvalidation-api-2.0.1.Final.jar;C:UsersAdministrator.m2
epositoryorgjbossloggingjboss-logging3.3.2.Finaljboss-logging-3.3.2.Final.jar;C:UsersAdministrator.m2
epositorycomfasterxmlclassmate1.3.4classmate-1.3.4.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-web5.0.7.RELEASEspring-web-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-webmvc5.0.7.RELEASEspring-webmvc-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworksecurityoauthspring-security-oauth22.3.3.RELEASEspring-security-oauth2-2.3.3.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-beans5.0.7.RELEASEspring-beans-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-core5.0.7.RELEASEspring-core-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-jcl5.0.7.RELEASEspring-jcl-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworkspring-context5.0.7.RELEASEspring-context-5.0.7.RELEASE.jar;C:UsersAdministrator.m2
epositoryorgspringframeworksecurityspring-security-core5.0.6.RELEASEspring-security-core-5.0.6.RELEASE.jar;C:UsersAdministrator.m2
epositorycommons-codeccommons-codec1.11commons-codec-1.11.jar;C:UsersAdministrator.m2
epositoryorgcodehausjacksonjackson-mapper-asl1.9.13jackson-mapper-asl-1.9.13.jar;C:UsersAdministrator.m2
epositoryorgcodehausjacksonjackson-core-asl1.9.13jackson-core-asl-1.9.13.jar;C:UsersAdministrator.m2
epositoryorgprojectlomboklombok1.16.22lombok-1.16.22.jar" com.cjs.example.CjsOauth2CodeServerApplication

  .   ____          _            __ _ _
 /\\ / ___‘_ __ _ _(_)_ __  __ _    ( ( )\\___ | ‘_ | ‘_| | ‘_ / _` |     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  ‘  |____| .__|_| |_|_| |_\\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.3.RELEASE)

2018-06-26 09:44:09.575  INFO 6528 --- [           main] c.c.e.CjsOauth2CodeServerApplication     : Starting CjsOauth2CodeServerApplication on USER-20170302XK with PID 6528 (E:cjsworkspacecjs-oauth2-examplecjs-oauth2-code-server	argetclasses started by Administrator in E:cjsworkspacecjs-oauth2-examplecjs-oauth2-code-server)
2018-06-26 09:44:09.597  INFO 6528 --- [           main] c.c.e.CjsOauth2CodeServerApplication     : No active profile set, falling back to default profiles: default
2018-06-26 09:44:09.762  INFO 6528 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.ser[email protected]22635ba0: startup date [Tue Jun 26 09:44:09 CST 2018]; root of context hierarchy
2018-06-26 09:44:12.931  INFO 6528 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-06-26 09:44:12.997  INFO 6528 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-06-26 09:44:12.998  INFO 6528 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2018-06-26 09:44:13.039  INFO 6528 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:Program FilesJavajdk1.8.0_152in;C:WindowsSunJavain;C:Windowssystem32;C:Windows;C:ProgramDataOracleJavajavapath;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:Program FilesJavajdk1.8.0_152in;C:Program FilesJavajdk1.8.0_152jrein;D:apacheapache-maven-3.5.3in;C:Program FilesGitcmd;.]
2018-06-26 09:44:13.200  INFO 6528 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-06-26 09:44:13.200  INFO 6528 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3448 ms
2018-06-26 09:44:13.379  INFO 6528 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: ‘characterEncodingFilter‘ to: [/*]
2018-06-26 09:44:13.379  INFO 6528 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: ‘hiddenHttpMethodFilter‘ to: [/*]
2018-06-26 09:44:13.379  INFO 6528 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: ‘httpPutFormContentFilter‘ to: [/*]
2018-06-26 09:44:13.379  INFO 6528 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: ‘requestContextFilter‘ to: [/*]
2018-06-26 09:44:13.379  INFO 6528 --- [ost-startStop-1] .s.DelegatingFilterProxyRegistrationBean : Mapping filter: ‘springSecurityFilterChain‘ to: [/*]
2018-06-26 09:44:13.380  INFO 6528 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-06-26 09:44:13.529  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/authorize]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
2018-06-26 09:44:13.530  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/authorize],methods=[POST],params=[user_oauth_approval]}" onto public org.springframework.web.servlet.View org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.approveOrDeny(java.util.Map<java.lang.String, java.lang.String>,java.util.Map<java.lang.String, ?>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
2018-06-26 09:44:13.530  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/token],methods=[POST]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
2018-06-26 09:44:13.531  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/token],methods=[GET]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
2018-06-26 09:44:13.531  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/check_token]}" onto public java.util.Map<java.lang.String, ?> org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.checkToken(java.lang.String)
2018-06-26 09:44:13.531  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/confirm_access]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint.getAccessConfirmation(java.util.Map<java.lang.String, java.lang.Object>,javax.servlet.http.HttpServletRequest) throws java.lang.Exception
2018-06-26 09:44:13.531  INFO 6528 --- [           main] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/error]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint.handleError(javax.servlet.http.HttpServletRequest)
2018-06-26 09:44:13.760  INFO 6528 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-26 09:44:14.019  INFO 6528 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.ser[email protected]22635ba0: startup date [Tue Jun 26 09:44:09 CST 2018]; root of context hierarchy
2018-06-26 09:44:14.049  INFO 6528 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-06-26 09:44:14.049  INFO 6528 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-06-26 09:44:14.062  INFO 6528 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-26 09:44:14.063  INFO 6528 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-26 09:44:14.103  WARN 6528 --- [           main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
2018-06-26 09:44:14.806  INFO 6528 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern=‘/oauth/token‘], Ant [pattern=‘/oauth/token_key‘], Ant [pattern=‘/oauth/check_token‘]]], [org.springframework.secu[email protected]5aae8eb5, org.spring[email protected]1473b8c0, [email protected]975, org.[email protected]5dc3fcb7, org.springfram[email protected]7a639ec5, org.springframework.security.web[email protected], org.springframework.[email protected]7a18e8d, org.springfram[email protected]76954a33, o[email protected]5972d253, org[email protected]2d195ee4, org.springfr[email protected]6fca2a8f]
2018-06-26 09:44:14.865  INFO 6528 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-06-26 09:44:14.901  INFO 6528 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ‘‘
2018-06-26 09:44:14.904  INFO 6528 --- [           main] c.c.e.CjsOauth2CodeServerApplication     : Started CjsOauth2CodeServerApplication in 6.298 seconds (JVM running for 8.287)

5.1. 授权端点

请求

参数名称 描述
response_type 必填。将其值设置为code表示如果成功的话将收到一个授权码。
client_id 必填。客户端标识。
redirect_uri 可选。重定向URI虽然不是必须的,但是你的服务应该会需要它。而且,这个URL必须和授权服务端注册的redirect_id一致。
scope 可选。请求可能会有一个或多个scope值。授权服务器会把客户端请求的范围(scope)展示给用户看。
state 推荐。state参数用于应用存储特定的请求数据的可以防止CSRF攻击。授权服务器必须原封不动地将这个值返回给应用。

 

 

 

 

 

 

 

 

例如:

http://localhost:8080/oauth/authorize?response_type=code&client_id=my-client-1&redirect_uri=http://www.baidu.com&scope=all

响应

参数名称 描述
code 授权码,稍后用此授权码交换访问令牌
state 请求时带的state参数

 

 

 

例如:

https://www.baidu.com/?code=7Zudn6

5.2. 令牌端点

请求

参数名称 描述
grant_type 必填。参数值必须是"authorization_code"
code 必填。之前收到的授权码
redirect_uri 可能是必填的。如果授权请求的时候有redirect_uri,那么token请求的时候也必须带上这个参数,二者的值必须是一样的。
client_id 客户端标识,如果没有其它的客户端认证存在的话这个参数是必须的。

 

 

 

 

 

 

关于客户端认证补充一点

技术分享图片

授权服务器可以通过HTTP Basic Auth方式对客户端进行认证,也可以通过在请求中加一个client_secret参数来对客户端进行认证。

不建议将客户端的secret直接作为参数放到client_secret中,而且这种方式下client_id和client_secret都是必填参数。

特别注意,用户(资源所有者)的用户名和密码跟客户端的用户名和密码(client_id、client_secret)不是一套,它们是两个东西。

那么,通过HTTP Basic Auth如何对客户端进行认证呢?客户端需要怎样传参呢?

需要在请求header中设置Authorization,它的值是Basic + 空格 + Base64加密后的client_id:secret

至于为什么,那是协议要求的,具体可以参考https://tools.ietf.org/html/rfc2617#page-5,格式如下:

技术分享图片

例如:

POST /oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: Basic bXktY2xpZW50LTE6MTIzNDU2Nzg=
cache-control: no-cache
Postman-Token: baf729b9-f030-41c1-b6fb-d740b0c5c573
User-Agent: PostmanRuntime/7.1.1
Accept: */*
Host: localhost:8080
cookie: JSESSIONID=45EAF00C9829B9F569579DB08533D850; UISESSION=2A65FF6FC8C6BE415DE3C043E3EDAAA4
accept-encoding: gzip, deflate
content-length: 103
Connection: keep-alive

grant_type=authorization_code&code=7Zudn6&redirect_uri=http%3A%2F%2Fwww.baidu.com&client_id=my-client-1

6. 客户端请求

技术分享图片

直接在浏览器中输入以下地址,然后会跳到登录授权页面

http://localhost:8080/oauth/authorize?response_type=code&client_id=my-client-1&redirect_uri=http://www.baidu.com&scope=all

技术分享图片

技术分享图片

上面这两个页面都是默认自带的

授权成功以后重定向

技术分享图片

有了授权码以后就可以换取access_token了

技术分享图片

技术分享图片

这个请求中唯一需要注意的一个参数就是Authorization,这是用于认证客户端的,本例中它是这样算出来的

public static void main(String[] args) {
    System.out.println(new org.apache.tomcat.util.codec.binary.Base64().encodeAsString("my-client-1:12345678".getBytes()));
    System.out.println(java.util.Base64.getEncoder().encodeToString("my-client-1:12345678".getBytes()));
}

所以,最终是Basic bXktY2xpZW50LTE6MTIzNDU2Nzg=

 

到此为止,我们只是获得了access_token,下一节将讲解如何配置资源服务器,以及客户端访问受保护的资源。

另外,本例中关于令牌的存储,以及客户端注册都是在内存中,实际生产过程中肯定是要存储到数据库中的,这一部分以后有时间再写吧!

 

以上是关于OAuth 2.0 授权码请求的主要内容,如果未能解决你的问题,请参考以下文章

OAuth 2.0实战-为什么要先获取授权码code?

OAuth 2.0 授权介绍和使用

无秘密的 OAuth 2.0 授权码授予

在 Angular 中实现 OAuth 2.0 授权代码授予

如何从单页应用程序实现 OAuth 2.0 授权码授予?

OAuth 2.0实现分布式认证授权-客户单和授权码存储数据库