# 实验四 基于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模板

```