# 码云第三方登录 **Repository Path**: chenhebin/expriment4 ## Basic Information - **Project Name**: 码云第三方登录 - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-05-15 - **Last Updated**: 2021-04-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ##

东莞理工学院网络空间安全学院

####

实验报告模板

课程名称:企业级开发框架专题                                 学期:2020春季

`实验名称`:利用Spring boot的自动装配特性实现动态注册组件    `实验序号`:四 `姓名`:陈和斌        `学号`:201741404201        `班级`:17软卓1班 `实验地址`:居家       `实验日期`:2020-5-18        `指导老师`:黎志雄 `教师评语`:XXX        `实验成绩`:XXX             `百分制`:XXX `同组同学`:无 #### 一、实验目标 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、 创建接入码云的应用。 #### `步骤`: 1). 在码云创建一个第三方应用,如下图所示:
2). 在idea中用静态变量将Client_ID和Client_Secret存起来,以便使用
##### 2、编写重定向过滤器的业务逻辑。 #### `步骤`: 在doFilterInternal()函数中添加代码如下: ``` UriComponents uriComponents = UriComponentsBuilder .fromUriString("https://gitee.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code") .build(); String uri = uriComponents.expand(CLIENT_ID, REDIRECT_URI).encode().toUriString(); response.sendRedirect(uri); ``` #### `说明`: ‘{}’是占位符,使用UriComponents动态生成uri;如果是/oauth2/gitee请求重定向到码云登录 ##### 3、使用码云access_token API向码云认证服务器发送post请求获取access_token。 #### `步骤`: 在getAccessToken()函数中添加如下代码: ``` UriComponents uriComponents = UriComponentsBuilder.fromUriString(ACCESS_TOKEN_API_URI).build(); URI uri = uriComponents.expand(code,CLIENT_ID,REDIRECT_URI,CLIENT_SECRET).encode().toUri(); MultiValueMap header = new LinkedMultiValueMap<>(); header.add("User-Agent","Mozilla/5.0"); RequestEntity requestEntity = new RequestEntity(header,HttpMethod.POST,uri); ResponseEntity responseEntity = rest.exchange(requestEntity,String.class); JacksonJsonParser jacksonJsonParser = new JacksonJsonParser(); Map map = jacksonJsonParser.parseMap(responseEntity.getBody()); return map.get("access_token").toString(); ``` #### `说明`: 先动态生成uri,构造一个带有"User_Agent"头部的post请求实体; 设置相应实体为String类型,接收相应内容; 返回的数据在响应体的body中,用JacksonJsonParser将json数据转换成java的map类型,从中提取所需的access_token并返回。 ##### 4、 使用码云API获取授权用户的资料。 #### `步骤`: 在getUserInfo()函数中添加如下代码: ``` UriComponents uriComponents = UriComponentsBuilder.fromUriString(USER_INFO_URI).build(); URI uri = uriComponents.expand(accessToken).encode().toUri(); MultiValueMap header = new LinkedMultiValueMap<>(); header.add("User-Agent","Mozilla/5.0"); RequestEntity requestEntity = new RequestEntity(header,HttpMethod.GET,uri); ResponseEntity responseEntity = rest.exchange(requestEntity,String.class); JacksonJsonParser jacksonJsonParser = new JacksonJsonParser(); Map userInfo = jacksonJsonParser.parseMap(responseEntity.getBody()); return userInfo; ``` #### `说明`: 先动态生成uri,构造一个带有"User_Agent"头部的GET请求实体,注意如果是POST会报错; 设置相应实体为String类型,接收相应内容; 返回的数据在响应体的body中,用JacksonJsonParser将json数据转换成java的map类型,返回用户信息。 ##### 5、把自定义的两个Filter加进安全过滤链。 #### `步骤`: 在configure()函数中添加如下代码: ``` GiteeOAuth2RedirectFilter giteeOAuth2RedirectFilter = new GiteeOAuth2RedirectFilter(); giteeOAuth2RedirectFilter = this.postProcess(giteeOAuth2RedirectFilter); GiteeOAuth2LoginAuthenticationFilter giteeOAuth2LoginAuthenticationFilter = new GiteeOAuth2LoginAuthenticationFilter(); giteeOAuth2LoginAuthenticationFilter = this.postProcess(giteeOAuth2LoginAuthenticationFilter); http.addFilterAfter(giteeOAuth2RedirectFilter,SecurityContextPersistenceFilter.class); http.addFilterAfter(giteeOAuth2LoginAuthenticationFilter,GiteeOAuth2RedirectFilter.class); ``` #### `说明`: 先将过滤器事例用.postProcess()方法处理一下,完成依赖注入 然后将两个过滤器添加到过滤链中, giteeOAuth2RedirectFilter添加在SecurityContextPersistenceFilter后面 giteeOAuth2LoginAuthenticationFilter添加在giteeOAuth2RedirectFilter后面 ##### 6、 把我们自定义的SecurityConfigurer应用到安全过滤链。 #### `步骤`: 1. 在configure()函数中添加两句代码,具体如下所示:
#### `说明`: 函数式编程应用自定义的GiteeOAuth2LoginConfigurer过滤链,需要实例化 ##### 7. 改造/user接口,返回码云用户资料给前端;改造user.ftlh模板用于显示用户资料。 #### `步骤`: 1)添加一个存储用户信息的实体类CustomUserDetails
2)将用户信息类set到authenticationToken中
3)将用户信息存到model中: ``` @GetMapping("/user") String userIndex(Model model) { model.addAttribute("customUserDetails",SecurityContextHolder.getContext().getAuthentication().getDetails()); return "user"; } ``` 4)前端展示用户信息: ``` 哎呀,出错了

${customUserDetails.login}

${customUserDetails.bio}

``` ##### 8、 编写单元测试。模拟一个登录用户,访问受保护的接口/test,断言接口的返回内容body部分是否一致。 #### `步骤`: 编写test()方法如下所示: ``` @Test @WithMockUser(username = "user",authorities = {"USER"}) public void test() throws Exception { mvc.perform(get("/test").header("User-Agent","Mozilla/5.0")) .andExpect(status().isOk()) .andExpect(content().string("访问/test接口成功,你拥有USER权限")); } ``` 说明: 1. @WithMockUser模拟了一个由"USER"权限的用户 2. 访问/test,断言返回的状态码是200,返回的数据是字符串"访问/test接口成功,你拥有USER权限" #### 四、实验结果 ##### 1、/test的测试结果
#### `说明`: 测试结果正确, /test接口的返回内容body部分一致 ##### 2、前端效果展示 浏览器地址栏输入“localhost:8080/user”,点击码云登录的图标:
#### `说明`: 已经登录授权过的,token没过期前会直接跳过验证过程;否则中间还会有登录授权的过程 #### 五、实验总结 ``` 1.本次实验让我们最spring security有的初步的认识 2.积累了一点使用第三方登录的经验 ```