# 实验四 基于Spring Security码云OAuth2认证的实验仓库
**Repository Path**: y1ip/spring-security-gitee-experiment-4
## Basic Information
- **Project Name**: 实验四 基于Spring Security码云OAuth2认证的实验仓库
- **Description**: 实验四 基于Spring Security码云OAuth2认证的实验仓库
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 71
- **Created**: 2020-12-02
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
#
**东莞理工学院网络空间安全学院**
#### **课程名称** :企业级开发框架专题 **学期:2020秋季**
`实验名称`:实验四 基于Spring Security码云OAuth2认证 `实验序号`:四
`姓名`:叶薰馥 `学号`:201841413237 `班级`:18网工2班
`实验地址`: `实验日期`:2020-11-30 `同组同学`:无
`指导老师`:黎志雄 `教师评语`: `实验成绩`:
# 实验四 基于Spring Security码云OAuth2认证
#### 一、实验目的
1、掌握使用Spring Security框架;
2、掌握使用Spring Security的安全过滤链;
3、掌握编写Spring Security单元测试;
4、掌握创建接入码云的应用;
5、掌握码云OAuth2认证基本流程;
6、掌握使用码云API;
7、了解使用模版引擎或前端框架制作用户登录界面
#### 二、实验环境
1、JDK 1.8或更高版本
2、Maven 3.6+
3、IntelliJ IDEA
#### 三、实验任务
1、登录码云,fork实验四的作业仓库。
2、根据下面的步骤填充代码,运行并测试成功:
1)OAuth2基本认证流程。
```java
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 用户认证前,构造一个GiteeOAuth2LoginAuthenticationToken
GiteeOAuth2LoginAuthenticationToken authenticationToken = (GiteeOAuth2LoginAuthenticationToken) authentication;
// 通过码云API获取access_token
String accessToken = getAccessToken(authenticationToken.getCode());
// 通过码云API获取Gitee授权用户的资料
Map userInfo = getUserInfo(accessToken);
// 认证成功后,重新生成Authentication
return createSuccessAuthentication(Objects.requireNonNull(userInfo), authenticationToken.getRequest());
}
```
码云OAuth2认证流程
2)步骤一:创建接入码云的应用。
```java
///////////////////////////////////////////////////
/// 步骤一:创建接入码云的应用,并把 CLIENT_ID 与 CLIENT_SECRET 赋值给下面的静态成员变量。
/// 参考:https://gitee.com/api/v5/oauth_doc#/list-item-3
static final String CLIENT_ID = "f224ce5b4b11c76cb620cb84c2fe18c4375b6c31fd09ad3dc523b4308e7d9662";
static final String CLIENT_SECRET = "a56b678f8271259195522232f0fe9416df23ff00503f65a9005b0b89889fe825";
///////////////////////////////////////////////////
```
3)步骤二:编写重定向过滤器的业务逻辑。
```java
// 应用通过 浏览器 或 Webview 将用户引导到码云三方认证页面上( GET请求 )
// 重定向地址:https://gitee.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code
//////////////////////////////////////////////////////////////
/// 步骤二:编写重定向过滤器的业务逻辑。
/// 当用户访问/oauth2/gitee时,本重定向过滤器拦截请求,并将用户重定向到码云三方认证页面上。
String uriString = UriComponentsBuilder.fromUriString("https://gitee.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code")
.encode()
.buildAndExpand(CLIENT_ID, REDIRECT_URI).toUriString();
response.sendRedirect(uriString);
//////////////////////////////////////////////////////////////
````
当用户访问/oauth2/gitee时,本重定向过滤器拦截请求,并将用户重定向到码云三方认证页面上
4)步骤三:使用码云access_token API向码云认证服务器发送post请求获取。
```java
////////////////////////////////////////////////////
/// 步骤三:使用码云access_token API向码云认证服务器发送post请求获取access_token。
URI uri = UriComponentsBuilder.fromUriString("https://gitee.com/oauth/token?grant_type=authorization_code&code={code}&client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}")
.encode()
.buildAndExpand(code, CLIENT_ID, REDIRECT_URI, CLIENT_SECRET).toUri();
RestTemplate rest= new RestTemplate();
RequestEntity requestEntity = RequestEntity.post(uri).header("User-Agent", "Dgut Demo").build();
ResponseEntity exchange = rest.exchange(requestEntity, String.class);
String result = exchange.getBody();
Map resultMap = new JacksonJsonParser().parseMap(result);
String access_tokenString = (String) resultMap.get("access_token");
return access_tokenString;
////////////////////////////////////////////////////
```
5)步骤四:使用码云API获取授权用户的资料。
```java
////////////////////////////////////////////////////
/// 步骤四:使用码云API获取授权用户的资料。
/// 参考:https://gitee.com/api/v5/swagger#/getV5User
URI uri = UriComponentsBuilder.fromUriString("https://gitee.com/api/v5/user?access_token={access_token}")
.encode()
.buildAndExpand(accessToken).toUri();
RestTemplate rest= new RestTemplate();
RequestEntity requestEntity = RequestEntity.get(uri).header("User-Agent", "Dgut Demo").build();
ResponseEntity exchange = rest.exchange(requestEntity, String.class);
String result = exchange.getBody();
Map resultMap = new JacksonJsonParser().parseMap(result);
return resultMap;
////////////////////////////////////////////////////
```
6)步骤五:把自定义的两个Filter加进安全过滤链。
```java
////////////////////////////////////////////////////////////////
/// 步骤五:把自定义的两个Filter加进安全过滤链
/// 注意:不要加在SecurityContextPersistenceFilter前面就行。
/// 参考:Spring Security内置的过滤器(注意它们的顺序,很重要)https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-security-filters
http.addFilterAfter(new GiteeOAuth2RedirectFilter(), LogoutFilter.class);
http.addFilterAfter(new GiteeOAuth2LoginAuthenticationFilter(),LogoutFilter.class);
////////////////////////////////////////////////////////////////
```
7)步骤六:把自定义的SecurityConfigurer应用到安全过滤链
```java
////////////////////////////////////////////////
/// 步骤六:把我们自定义的SecurityConfigurer应用到安全过滤链
http.apply(new GiteeOAuth2LoginConfigurer<>());
////////////////////////////////////////////////
```
8)步骤七:改造/user接口,返回码云资料给前端;改造user.ftlh模版用于显示用户资料。
```java
////////////////////////////////////
/// 步骤七:改造/user接口,返回码云用户资料给前端;改造user.ftlh模板用于显示用户资料。
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal = authentication.getPrincipal();
URI uri = UriComponentsBuilder.fromUriString("https://gitee.com/api/v5/users/" + ((GiteeOAuth2LoginConfigurer.GiteeUserDetail)principal).getUserlogin())
.build(42);
RestTemplate rest= new RestTemplate();
RequestEntity requestEntity = RequestEntity.get(uri).header("User-Agent", "Dgut Demo").build();
ResponseEntity exchange = rest.exchange(requestEntity, String.class);
String result = exchange.getBody();
Map resultMap = new JacksonJsonParser().parseMap(result);
model.addAttribute("userInfo", resultMap);
return "user";
////////////////////////////////////
```
user.ftlh模板
```