客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。oAuth 2.0 定义了四种授权方式。
我们这里,主要写一个授权码模式的实例
创建一个名为 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
类
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
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);
}
}
创建 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");
}
}
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
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 + '\'' +
'}';
}
}
server:
port: 8081
spring:
mvc:
view:
suffix: .html
Title
账号:
密码:
第三方登入
输入http://localhost:8081/跳转到登入页面
选择第三方登入后跳转到
输入你在认证服务器写的账号密码
跳转
根据授权码获取用户资源还没弄,以后再更!!!