OR博客
【OAuth2】第三方客户端接入——登录流程
苗锦洲
创建于:2022-04-07 19:31:52
0
27
180
0
OAuth2第三方客户端登录流程
### 登录流程 1. 先注册第三方客户端 2. 安卓端构建OAuth2授权链接 3. 认证服务器重定向到注册时填的redirect_uri 4. 接收code,换取access_token,获取Openid 5. 使用Openid登录IoE模块 6. 根据Openid判断IoE模块是否存在用户 7. 未存在则先使用access_token换取userinfo,拿到email、username,创建Customer、创建User、激活User、创建IoE用户 8. 已存在则直接将access_token和satoken和state传回authorized.html 9. 网页构建打开APP的URI,提前在APP中设置好 10. APP接收state、access_token和satoken 11. APP先判断state是否一致,不一致/access_token或satoken为空则提示登录失败 12. APP使用access_token向OAuth2服务器换取userinfo,保存用户信息 13. APP保存用于访问IoE模块的satoken 14. APP端登录完成 ### 后端代码 ```java /* * MIT License * * Copyright (c) 2021 苗锦洲 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * @author mjz * @date 2022/3/22 */ @Slf4j @RequiredArgsConstructor @RestController public class IoEController implements IIoEApi { private final OAuth2ClientProperties oAuth2ClientProperties; private final IIoEUserFacade ioEUserFacade; private final IoEUserService userService; private final IOAuth2Api oAuth2Api; private final OrThingsBoardProperties thingsBoardProperties; private final OrThingsBoardCustomerService thingsBoardCustomerService; private final OrThingsBoardUserService thingsBoardUserService; @Transactional(rollbackFor = BaseException.class) @Override public ModelAndView authorized( @RequestParam(required = false) String code, @RequestParam(required = false) String state, // refuse @RequestParam(required = false) String handle, // 拒绝消息 @RequestParam(required = false) String msg ) { log.info("auth-server登录成功回调:{},{}", code, state); // 1. 用code获取Openid和AccessToken JSONObject params = new JSONObject(); params.put(SaOAuth2Consts.Param.grant_type, SaOAuth2Consts.GrantType.authorization_code); params.put(SaOAuth2Consts.Param.code, code); params.put(SaOAuth2Consts.Param.client_id, oAuth2ClientProperties.getClientId()); params.put(SaOAuth2Consts.Param.client_secret, oAuth2ClientProperties.getClientSecret()); params.put(SaOAuth2Consts.Param.state, state); // 需要将结果封装 params.put("wrapped", true); Result<JSONObject> response = Result.parse( HttpUtil.get(oAuth2ClientProperties.getAuthServerHost() + SaOAuth2Consts.Api.token, params) ); // code不等于200 代表请求失败 if (response == null) { throw new BaseException(StatusCode.COMMON_FAIL); } if (!response.getSuccess()) { throw new BaseException(response.getMsg()); } JSONObject data = response.getData(); log.info("IoE authorized(), 1. AccessToken: {}", data); final String accessToken = data.getString("access_token"); String openid = data.getString("openid"); // 2. 使用Openid登录IoE StpUtil.login(openid, Boolean.TRUE); final String tokenValue = StpUtil.getTokenValue(); log.info("IoE authorized(), 2. login successfully.,\nAccessToken: {}\nOpenid:{}\nSaToken:{}", data, openid, tokenValue); // 3. 根据openid查询IoE User是否存在,不存在则直接创建 final IoEUserQueryRequest request = new IoEUserQueryRequest(); request.setOpenid(openid); final Result<IoEUserDTO> ioeUserResult = ioEUserFacade.findByUniqueColumn(request); IoEUserDTO ioEUserDTO; if (ioeUserResult.getSuccess()) { log.info("IoE authorized(), 3. IoEUser already existed, skip create"); ioEUserDTO = ioeUserResult.getData(); } else { log.info("IoE authorized(), 3.1/5 IoEUser not exist, creating..."); // 获取userinfo final OAuth2UserinfoRequest oAuth2UserinfoRequest = new OAuth2UserinfoRequest(); oAuth2UserinfoRequest.setAccessToken(accessToken); final Result<OAuth2UserInfoDTO> userinfoResult = oAuth2Api.userinfo(oAuth2UserinfoRequest); if (!userinfoResult.getSuccess()) { throw new BaseException(userinfoResult.getMsg()); } final OAuth2UserInfoDTO userInfoDTO = userinfoResult.getData(); final SysUserDTO sysUserDTO = userInfoDTO.getUser(); final String defaultUsername = sysUserDTO.getUsername(); // 创建Customer final String tenantId = thingsBoardProperties.getTenant().getId(); final Customer customer = thingsBoardCustomerService.create(tenantId, null, defaultUsername); log.info("IoE authorized(), 3.2/5 ThingsBoard Customer created successfully, {}", customer); // 创建Customer下的User final String customerId = customer.getId().toString(); final String email = sysUserDTO.getEmail(); final User user = thingsBoardUserService.create(email, defaultUsername, null, tenantId, customerId); log.info("IoE authorized(), 3.3/5 ThingsBoard User created successfully, {}", user); // 直接激活User final String userId = user.getId().toString(); thingsBoardUserService.active(userId); log.info("IoE authorized(), 3.4/5 ThingsBoard User activation succeeded"); // 创建新IoE用户 final IoEUserSaveRequest ioEUserSaveRequest = new IoEUserSaveRequest(); ioEUserSaveRequest.setOpenid(openid); ioEUserSaveRequest.setCustomerId(customerId); ioEUserSaveRequest.setUserId(userId); ioEUserSaveRequest.setUsername(defaultUsername); final Result<IoEUserDTO> ioEUserDTOResult = ioEUserFacade.create(ioEUserSaveRequest); if (!ioEUserDTOResult.getSuccess()) { throw new BaseException(ioEUserDTOResult.getMsg()); } ioEUserDTO = ioEUserDTOResult.getData(); log.info("IoE authorized(), 3.5/5 IoEUser successfully created"); } // 4. 处理完毕,传参到网页进行重定向 Map<String, Object> map = new HashMap<>(3); map.put(SaOAuth2Consts.Param.access_token, accessToken); map.put("satoken", tokenValue); map.put(SaOAuth2Consts.Param.state, state); log.info("IoE authorized(), 4. Finished, IoEUser: {}", ioEUserDTO); return new ModelAndView("authorized.html", map); } @Override public Result<IoEUserinfoDTO> userinfo() { final IoEUserinfoDTO ioEUserinfoDTO = new IoEUserinfoDTO(); final String openid = StpUtil.getLoginIdAsString(); final IoEUserQueryRequest request = new IoEUserQueryRequest(); request.setOpenid(openid); final Result<IoEUserDTO> ioeUserResult = ioEUserFacade.findByUniqueColumn(request); if (!ioeUserResult.getSuccess()) { return Result.fail(); } ioEUserinfoDTO.setUser(ioeUserResult.getData()); return Result.success(ioEUserinfoDTO); } @Override public Result<JsonNode> thingsboardToken() { final String openid = StpUtil.getLoginIdAsString(); final Optional<IoEUserDO> optional = userService.findByOpenid(openid); return optional.map(ioEUserDO -> Result.success(thingsBoardUserService.getToken(ioEUserDO.getUserId()))).orElse(Result.fail()); } } ```
评论