Spring Security oAuth2之授权码模式

概述

客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。oAuth 2.0 定义了四种授权方式。

  • implicit:简化模式,不推荐使用
  • authorization code:授权码模式
  • resource owner password credentials:密码模式
  • client credentials:客户端模式

我们这里,主要写一个授权码模式的实例

Spring Security oAuth2 创建项目工程

工程

创建一个名为 hello-spring-security-oauth2 工程项目,POM 如下:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
         
    

    com.rsxtar
    hello-spring-security-oauth2
    0.0.1-SNAPSHOT
    pom
    http://www.rsxtar.com

    
        hello-spring-security-oauth2-dependencies
        hello-spring-security-oauth2-server
        hello-spring-security-oauth2-client
        hello-spring-security-oauth2-common
    

    
        1.8
        ${java.version}
        ${java.version}
        UTF-8
        UTF-8
    



    
        
            
                com.rsxtar
                hello-spring-security-oauth2-dependencies
                ${project.version}
                pom
                import
            
        
    

    
        
            default
            
                true
            
            
                0.0.12
            
            
                
                    
                        io.spring.javaformat
                        spring-javaformat-maven-plugin
                        ${spring-javaformat.version}
                    
                    
                        org.apache.maven.plugins
                        maven-surefire-plugin
                        
                            
                                **/*Tests.java
                            
                            
                                **/Abstract*.java
                            
                            
                                file:/dev/./urandom
                                true
                            
                        
                    
                    
                        org.apache.maven.plugins
                        maven-enforcer-plugin
                        
                            
                                enforce-rules
                                
                                    enforce
                                
                                
                                    
                                        
                                            
                                                commons-logging:*:*
                                            
                                            true
                                        
                                    
                                    true
                                
                            
                        
                    
                    
                        org.apache.maven.plugins
                        maven-install-plugin
                        
                            true
                        
                    
                    
                        org.apache.maven.plugins
                        maven-javadoc-plugin
                        
                            true
                        
                        true
                    
                
            
        
    

    
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    

    
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    

依赖管理项目

创建一个名为 hello-spring-security-oauth2-dependencies 项目,POM 如下:



    4.0.0

    com.rsxtar
    hello-spring-security-oauth2-dependencies
    0.0.1-SNAPSHOT
    pom
    http://www.rsxtar.com

    
        Greenwich.RELEASE
    



    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    

    
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    

    
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    


项目共同方法

创建一个名为 hello-spring-security-oauth2-common 项目,POM 如下:



    4.0.0

    com.rsxtar
    hello-spring-security-oauth2-common
    0.0.1-SNAPSHOT
    
        
            org.apache.httpcomponents
            httpclient
            4.5.9
        
        
            org.apache.commons
            commons-lang3
            3.8.1
        
    
    pom
    http://www.rsxtar.com



hello-spring-security-oauth2-common创建HttpClientTool
Spring Security oAuth2之授权码模式_第1张图片

package hello.spring.security.oauth2.common.kit;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

/**
 * 基于 httpclient 4.5版本的 http工具类
 *
 *
 */
public class HttpClientTool {

    private static final CloseableHttpClient httpClient;
    public static final String CHARSET = "UTF-8";
    // 采用静态代码块,初始化超时时间配置,再根据配置生成默认httpClient对象
    static {
        RequestConfig config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(15000).build();
        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
    }

    public static String doGet(String url, Map params) {
        return doGet(url, params, CHARSET);
    }

    public static String doGetSSL(String url, Map params) {
        return doGetSSL(url, params, CHARSET);
    }

    public static String doPost(String url, Map params) throws IOException {
        return doPost(url, params, CHARSET);
    }

    /**
     * HTTP Get 获取内容
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doGet(String url, Map params, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            if (params != null && !params.isEmpty()) {
                List pairs = new ArrayList(params.size());
                for (Map.Entry entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                // 将请求参数和url进行拼接
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            }
            HttpGet httpGet = new HttpGet(url);
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * HTTP Post 获取内容
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     * @throws IOException
     */
    public static String doPost(String url, Map params, String charset)
            throws IOException {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        List pairs = null;
        if (params != null && !params.isEmpty()) {
            pairs = new ArrayList(params.size());
            for (Map.Entry entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
        }
        HttpPost httpPost = new HttpPost(url);
        if (pairs != null && pairs.size() > 0) {
            httpPost.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
        }
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            return result;
        } catch (ParseException e) {
            e.printStackTrace();
        } finally {
            if (response != null){
                response.close();
            }

        }
        return null;
    }

    /**
     * HTTPS Get 获取内容
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset  编码格式
     * @return 页面内容
     */
    public static String doGetSSL(String url, Map params, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            if (params != null && !params.isEmpty()) {
                List pairs = new ArrayList(params.size());
                for (Map.Entry entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            }
            HttpGet httpGet = new HttpGet(url);

            // https  注意这里获取https内容,使用了忽略证书的方式,当然还有其他的方式来获取https内容
            CloseableHttpClient httpsClient = HttpClientTool.createSSLClientDefault();
            CloseableHttpResponse response = httpsClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 这里创建了忽略整数验证的CloseableHttpClient对象
     * @return
     */
    public static CloseableHttpClient createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return HttpClients.createDefault();
    }
}

创建认证服务器

创建一个名为 hello-spring-security-oauth2-server 项目,POM 如下:



    4.0.0

    
        com.rsxtar
        hello-spring-security-oauth2
        0.0.1-SNAPSHOT
    


    com.rsxtar
    hello-spring-security-oauth2-server
    0.0.1-SNAPSHOT
    jar
    http://www.rsxtar.com



    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-test
        

        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
            
                  
                    org.springframework.security.oauth.boot
                    spring-security-oauth2-autoconfigure
                
            
        


        
            org.springframework.security.oauth.boot
            spring-security-oauth2-autoconfigure
            2.1.6.RELEASE
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    com.rsxtar.spring.security.oauth2.server.OAuth2ServerApplication
                
            
        
    


Application

package com.rsxtar.spring.security.oauth2.server;

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

/**
 * @author rsxtar
 * @date 2019/07/12下午 05:08
 */
@SpringBootApplication
public class OAuth2ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OAuth2ServerApplication.class,args);
    }
}

创建configure
Spring Security oAuth2之授权码模式_第2张图片

配置认证服务器

创建 AuthorizationServerConfiguration

package com.rsxtar.spring.security.oauth2.server.configure;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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;


/**
 * @author rsxtar
 * @date 2019/07/12下午 08:09
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置客户端
        clients
                // 使用内存设置
                .inMemory()
                // client_id
                .withClient("client")
                // client_secret
                .secret(passwordEncoder.encode("secret"))
                // 授权类型
                .authorizedGrantTypes("authorization_code")
                // 授权范围
                .scopes("app")
                // 注册回调地址
                .redirectUris("http://localhost:8081/getCode");


    }
}

服务器安全配置

创建WebSecurityConfiguration

package com.rsxtar.spring.security.oauth2.server.configure;

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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @author rsxtar
 * @date 2019/07/12下午 05:12
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        //配置默认的加密方式
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 在内存中创建用户
        auth.inMemoryAuthentication()
                .withUser("user").password(passwordEncoder().encode("123456")).roles("USER")
                .and()
                .withUser("admin").password(passwordEncoder().encode("admin888")).roles("ADMIN");
    }
}

application.yml

spring:
application:
name: oauth2-server

server:
port: 8080

配置客户端

创建一个名为 hello-spring-security-oauth2-client 项目,POM 如下:



    4.0.0

    
        com.rsxtar
        hello-spring-security-oauth2
        0.0.1-SNAPSHOT
    
    com.rsxtar
    hello-spring-security-oauth2-client
    0.0.1-SNAPSHOT
    jar
    http://www.rsxtar.com

    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-test
    
    
    
        org.apache.oltu.oauth2
        org.apache.oltu.oauth2.client
        1.0.2
    
    
    
        javax.servlet
        javax.servlet-api
        4.0.1
        provided
    
    
        com.rsxtar
        hello-spring-security-oauth2-common
        0.0.1-SNAPSHOT
    
    
    
        com.alibaba
        fastjson
        1.2.58
    



Spring Security oAuth2之授权码模式_第3张图片
ClientController内容为

package hello.spring.security.oauth2.client.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import hello.spring.security.oauth2.client.domain.ReceptionService;
import hello.spring.security.oauth2.client.domain.Send;
import hello.spring.security.oauth2.common.kit.HttpClientTool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author rsxtar
 * @date 2019/07/12下午 08:57
 */
@Controller
public class ClientController {
    @Autowired
    Send send;

    @GetMapping("/")
    public String Test(){
        return "login";
    }

    @GetMapping("/getCode")
    public String getCode( String code){
        Map map = new HashMap<>();
        map.put("code",code);
        map.put("grant_type","authorization_code");
        try {
            String s = HttpClientTool.doPost("http://client:secret@localhost:8080/oauth/token", map);
            JSONObject userJson = JSONObject.parseObject(s);
            ReceptionService receptionService = JSON.toJavaObject(userJson,ReceptionService.class);
            System.out.println(receptionService);
        } catch (IOException e) {
            e.printStackTrace();

            return "eor";
        }

        return "succeed";
    }

}

ReceptionService

package hello.spring.security.oauth2.client.domain;
import org.springframework.stereotype.Component;

import	java.io.PrintWriter;
import	java.security.PrivateKey;
import	java.security.Provider;
import	java.time.Period;

/**
 * @author rsxtar
 * @date 2019/07/13下午 02:37
 */
@Component
public class ReceptionService {
    private String access_token;
    private String expires_in;
    private String token_type;
    private String scope;

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(String expires_in) {
        this.expires_in = expires_in;
    }

    public String getToken_type() {
        return token_type;
    }

    public void setToken_type(String token_type) {
        this.token_type = token_type;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    @Override
    public String toString() {
        return "ReceptionService{" +
                "access_token='" + access_token + '\'' +
                ", expires_in='" + expires_in + '\'' +
                ", token_type='" + token_type + '\'' +
                ", scope='" + scope + '\'' +
                '}';
    }
}

application.yml

server:
  port: 8081

spring:
  mvc:
    view:
      suffix: .html

登录页面




    
    Title


账号: 
密码:
第三方登入

输入http://localhost:8081/跳转到登入页面
选择第三方登入后跳转到
Spring Security oAuth2之授权码模式_第4张图片
输入你在认证服务器写的账号密码
跳转
Spring Security oAuth2之授权码模式_第5张图片
根据授权码获取用户资源还没弄,以后再更!!!

你可能感兴趣的:(Spring Security oAuth2之授权码模式)