SpringBoot整合OAuth2和Jwt实现第三方登录

SpringBoot整合OAuth2和Jwt实现第三方登录

一、OAuth2的使用场景
  • 现代微服务中系统微服务化以及应用的形态和设备类型增多,不能用传统的登录方式
  • 核心的技术不是用户名和密码,而是token,由AuthServer颁发token,用户使用token进行登录

在这里插入图片描述

二、OAuth详解
2.1 什么是OAuth

在这里插入图片描述

2.2 OAuth的优势

在这里插入图片描述

2.3 OAuth术语

在这里插入图片描述在这里插入图片描述

2.4 OAuth2令牌的类型

在这里插入图片描述

三、和SpringBoot整合
3.1 准备工作
  1. 首先注册微信开放平台账号 微信开放平台
  2. 邮箱激活
  3. 完善开发者资料
  4. 开发者资质认证
    4.1 准备营业执照,1-2个工作日审批、300元
  5. 创建网站应用
    5.1 提交审核,7个工作日审批
  6. 熟悉微信登录流程 参考文档
3.2 请求微信登录流程图

微信登录请求流程图

3.3 添加配置文件
# outh2相关配置
wx:
  open:
    #微信开放平台 appid
    app_id: xxxxxxxxxxxxxxx
    # 微信开放平台 appsecret
    app_secret: xxxxxxxxxxxxxxxxx
    # 微信开放平台 重定向url(guli.shop需要在微信开放平台配置)
    redirect_url: http://xxxxxxxxxxx

3.4 将相关信息做成配置类
@Component
//@PropertySource("classpath:application.yml")
public class ConstantPropertiesUtil implements InitializingBean {

	@Value("${wx.open.app_id}")
	private String appId;

	@Value("${wx.open.app_secret}")
	private String appSecret;

	@Value("${wx.open.redirect_url}")
	private String redirectUrl;

	public static String WX_OPEN_APP_ID;
	public static String WX_OPEN_APP_SECRET;
	public static String WX_OPEN_REDIRECT_URL;

	@Override
	public void afterPropertiesSet() throws Exception {
		WX_OPEN_APP_ID = appId;
		WX_OPEN_APP_SECRET = appSecret;
		WX_OPEN_REDIRECT_URL = redirectUrl;
	}
}
3.5 定义请求登录方法
	@GetMapping("/ucenterService/login")
	@ApiOperation("生成微信扫描二维码")
	public String genQrConnect(HttpSession session) {
		LOGGER.info("生成微信扫描二维码  start ");
	/*	固定地址,后面拼接参数
       String url = "https://open.weixin.qq.com/" +
                "connect/qrconnect?appid="+ ConstantWxUtils.WX_OPEN_APP_ID+"&response_type=code";*/


		// 微信开放平台授权baseUrl %s相当于?代表占位符(此地址为固定地址,固定参数 )
		String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
				"?appid=%s" +
				"&redirect_uri=%s" +
				"&response_type=code" +
				"&scope=snsapi_login" +
				"&state=%s" +
				"#wechat_redirect";
		// 回调地址
		// 获取业务服务器重定向地址(需要在微信开放平台配置)
		String redirectUrl = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
		try {
			//对redirect_url进行URLEncoder编码
			redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(20001, e.getMessage());
		}

		// 防止csrf攻击(跨站请求伪造攻击)
		//String state = UUID.randomUUID().toString().replaceAll("-", "");//一般情况下会使用一个随机数

		//  这里填写你在ngrok的前置域名
		String state = "xxxx";
		LOGGER.info("state = {}", state);

		// 采用redis等进行缓存state 使用sessionId为key 30分钟后过期,可配置
		//键:"wechar-open-state-" + httpServletRequest.getSession().getId()
		//值:satte
		//过期时间:30分钟

		// 生成qrcodeUrl
		String qrcodeUrl = String.format(
				baseUrl,
				ConstantWxUtils.WX_OPEN_APP_ID,
				redirectUrl,
				state
		);

		LOGGER.info("生成微信扫描二维码  end 重定向地址为:{}", qrcodeUrl);
		return "redirect:" + qrcodeUrl;
	}
参数是否必须说明
appid应用唯一标识
redirect_uri请使用urlEncode对链接进行处理
response_type填code
scope应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即
state用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

请求登录的流程大致是这样子的:

  1. 首先请求一个固定的地址(该地址由微信官方提供,我们只需要按照要求提供相应的参数来调用即可)
  2. 为了安全性,redirect_url需要进行URLEncoder编码
  3. 请求完成后,微信会返回给我们一个地址,我们只需要重定向到该地址,就可以在该页面看到相应的二维码信息。
  4. 在我们扫码点击登录后,微信官方就会将我们的请求转发到我们的回调方法上(需要自己配置),我们在回调方法上来进行一些数据的操作。
3.6 回调方法
	@GetMapping("callback")
	@ApiOperation(value = "获取扫描人信息,添加数据", tags = "当用户扫描二维码登录后,会回调到本方法中")
	public String callback(String code, String state, HttpSession session) {
		LOGGER.info("用户微信扫描登陆之后开始进行回调: code = {},state = {}", code, state);

		// 从redis中将state获取出来,和当前传入的state作比较(正确的做法)
		// 如果一致则放行,如果不一致则抛出异常:非法访问(正确的做法)

		try {
			// 1 获取code值,临时票据,类似于验证码
			// 2 拿着code请求 微信固定的地址,得到两个值 accsess_token 和 openid
			// 向认证服务器发送请求换取access_token
			String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
					"?appid=%s" +
					"&secret=%s" +
					"&code=%s" +
					"&grant_type=authorization_code";

			// 拼接三个参数 :id  秘钥 和 code值
			String accessTokenUrl = String.format(baseAccessTokenUrl,
					ConstantWxUtils.WX_OPEN_APP_ID,
					ConstantWxUtils.WX_OPEN_APP_SECRET,
					code);

			// 请求这个拼接好的地址,得到返回两个值 accsess_token 和 openid
			// 使用httpclient发送请求,得到返回结果
			String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
			LOGGER.info("accessTokenInfo = {}", accessTokenInfo);
			// 从accessTokenInfo字符串获取出来两个值 accsess_token 和 openid
			// 把accessTokenInfo字符串转换map集合,根据map里面key获取对应值
			// 使用json转换工具 Gson
			Gson gson = new Gson();
			HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
			String accsess_token = (String) mapAccessToken.get("access_token");
			String openid = (String) mapAccessToken.get("openid");

			LOGGER.info("成功得到accsess_token和openid  accsess_token = {},openid = ", accsess_token, openid);
			// 把扫描人信息添加数据库里面
			// 判断数据表里面是否存在相同微信信息,根据openid判断(openid是唯一的)
			xXXXX   XXX  = xxxxService.getOpenId(openid);

			// 之前没有用微信登陆过
			if (null == XXXX) {
				LOGGER.info("当前用户尚未使用过微信登录,将会该用户的信息存入数据库");
				// 3 拿着得到accsess_token 和 openid,再去请求微信提供固定的地址,获取到扫描人信息
				// 访问微信的资源服务器,获取用户信息
				String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
						"?access_token=%s" +
						"&openid=%s";
				//拼接两个参数
				String userInfoUrl = String.format(
						baseUserInfoUrl,
						accsess_token,
						openid
				);
				// 发送请求,得到微信官方返回的用户信息
				String userInfo = HttpClientUtils.get(userInfoUrl);
				LOGGER.info("微信官方返回的用户信息为:{}", userInfo);
				//获取返回userinfo字符串扫描人信息
				HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
				String nickname = (String) userInfoMap.get("nickname");//昵称
				String headimgurl = (String) userInfoMap.get("headimgurl");//头像



				//将用户的头像信息和昵称存入数据库  略
				




				LOGGER.info("成功将微信信息存入数据库中,存入的信息为:{}", member);
			}
			LOGGER.info("当前用户已经使用过微信进行登录,直接返回该用户的信息");
			// TODO 登录

			// 生成jwt
			String token = JwtUtils.getJwtToken(xxx.getId(), xxx.getNickname());

			// 存入cookie
			//CookieUtils.setCookie(request, response, "guli_jwt_token", token);

			//  因为端口号不同存在跨域问题,cookie不能跨域,所以这里使用url重写

			LOGGER.info("微信登陆成功后重定向到首页,携带的token信息为:{}", token );
			return "redirect:http://xxx:xxxx?token=" + token;

		} catch (Exception e) {
			LOGGER.error("微信登录失败,异常信息为:{}", e.toString());
			throw new RunTimeException(20001, "登录失败");
		}
	}

回调方法简介

  1. 首先我们可以直接在请求参数中添加code 和 state,这两个信息就类似于验证码,我们在通过这两个数据去请求微信固定的地址,得到两个值accsess_token 和 openid 微信返回的数据为JSON格式,我们可以通过fastJson或其他来将数据转换为Map集合,在通过map集合来取到其中的这两个数据。
  2. 然后在通过accsess_token 和 openid这两个数据请求另一个微信官方的地址来获取微信账号的信息(包括微信账号的头像地址和微信名称)
  3. 获取到这些信息之后,便可一通过openid(唯一标识)进行判断,来判断用户之前是否使用过微信登录,如果没有登陆过,就可以将用户信息保存到数据库中。
  4. 使用JWT公具类来根据用户的openid和微信昵称来生成token
  5. 微信登陆成功后重定向到到目标页面,并且携带token信息
  6. 前端页面从请求路径中达到token信息,将token存储在cookie或者请头头中。
  7. 用户携带token请求用户信息,后端解析通过,将用户信息返回给前端,前端将用户信息作展示。
3.7 前端页面拦截请求路径的token并存储在cookie中
export default {
  data() {
    return {
      token: '',
      	   }
    },
     created() {
    this.token = this.$route.query.token
    if (this.token) {
      this.wxLogin()
    }
  }, 
methods: {
    wxLogin() {
      if (this.token == '') return
      //把token存在cookie中、也可以放在localStorage中
      cookie.set('guli_token', this.token, {domain: 'localhost'})
      cookie.set('guli_ucenter', '', {domain: 'localhost'})
      //登录成功根据token获取用户信息
      userApi.getLoginInfo().then(response => {
        this.loginInfo = response.data.data.item
        //将用户信息记录cookie
        cookie.set('guli_ucenter', this.loginInfo, {domain: 'localhost'})
      })
    }
  }
}

其中涉及到的jwt工具类和HttpClientUtils可以私聊我,我私发给你

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Spring Boot可以集成OAuth2和JWT实现安全的身份验证和授权。OAuth2是一种授权框架,允许用户授权第三方应用程序访问他们的资源。JWT是一种JSON Web Token,用于在客户端和服务器之间传递安全信息。 要集成OAuth2和JWT,需要使用Spring Security和Spring Boot Starter Security。首先,需要配置OAuth2客户端和服务器端,以便客户端可以通过服务器端进行身份验证和授权。然后,需要配置JWT令牌,以便客户端可以使用令牌来访问受保护的资源。 在配置完成后,可以使用Spring Security的注释和过滤器来保护应用程序的资源。例如,可以使用@PreAuthorize注释来限制只有特定角色或权限的用户才能访问某些资源。 总之,Spring Boot集成OAuth2和JWT可以帮助开发人员实现安全的身份验证和授权,保护应用程序的资源免受未经授权的访问。 ### 回答2: SpringBoot是一种用于构建微服务的框架,它提供了许多便捷的功能,比如自动配置、内嵌容器等。OAuth2和JWT是现代Web应用程序中的两个关键技术,用于确保安全性和授权。本文将介绍如何使用SpringBoot集成OAuth2和JWTOAuth2是一个用于授权的开放标准,它让第三方可以利用某个授权服务器允许的授权进行访问。OAuth2有四种授权模式:授权码、简化模式、密码模式和客户端模式。其中,授权码模式和简化模式是最常用的。 为了实现集成OAuth2,我们需要以下几个步骤: 1. 添加Maven依赖。我们需要添加spring-security-oauth2和spring-security-jwt的依赖,这两个依赖用于构建我们的安全框架。 2. 创建一个安全配置类。我们可以使用@EnableAuthorizationServer和@EnableResourceServer注释来标记该类。这两个注释指示SpringBoot使用OAuth2和JWT作为授权和安全框架。 3. 配置OAuth2的凭据和权限。我们需要提供OAuth2服务器的凭据,这些凭据将用于授权客户端和资源服务器。此外,我们还需要配置每个客户端的权限。我们可以使用AuthorizationServerConfigurerAdapter类中的configure(ClientDetailsServiceConfigurer)方法来完成此操作。 4. 配置JWT的秘钥。JWT是一种基于JSON的开放标准,用于安全地传输信息。为了确保JWT的安全性,我们需要使用签名算法生成JWT的签名。我们可以使用AuthorizationServerConfigurerAdapter类中的tokenStore()方法和JwtAccessTokenConverter类来配置JWT。 以上就是SpringBoot集成OAuth2和JWT的基本步骤。集成后我们可以通过OAuth2获取访问令牌,并使用JWT对其进行签名和验证。这种集成为我们的应用程序带来了更高的安全性和授权功能,是现代Web应用程序中不可或缺的技术之一。 ### 回答3: OAuth2是目前公认的授权协议标准之一,它通过提供授权访问令牌的方式,实现了无需暴露用户凭证即可访问受保护的数据资源。 Spring Boot提供了许多集成Spring Security的方式,其中就包括对OAuth2的支持。Spring Boot OAuth2集成可帮助我们在应用程序中实现授权和认证的功能。 JWT是一种轻量级的认证和授权机制,在认证成功后,服务器会生成一个基于JSON的令牌,该令牌包含有关用户身份的信息,然后将其发送回客户端。客户端使用此令牌可以访问应用程序的资源。 Spring Boot同样支持对JWT的集成,以便在服务器端和客户端之间完成对称加密和解密的过程。 Spring Boot集成OAuth2和JWT通常需要实现以下步骤: 1. 添加依赖关系:为了使用OAuth2和JWT,我们需要在项目中添加相应的依赖关系。可以使用Maven或Gradle工具来添加依赖关系。 2. 配置OAuth2:在配置文件中添加OAuth2支持的客户端信息、访问令牌的有效期、授权服务器地址、安全配置和JWT密钥等信息。 3. 实现授权服务器:我们需要在应用程序中实现授权服务器,以便为已注册的客户端颁发令牌。这通常需要实现一些Spring Security过滤器,并添加一些额外的配置类来处理OAuth2请求和响应。 4. 注册用户服务:可以使用内存或数据库来存储用户信息,并使用Spring Security提供的相关类来注册用户服务。 5. 实现保护资源:添加Spring Security配置类以保护资源,访问这些资源需要提供有效的令牌。 6. 添加自定义JWT:如果需要自定义JWT,则需要添加Spring Security配置类,并实现相关的JWT生成和验证代码。 总之,Spring Boot的OAuth2和JWT支持让我们在应用程序中实现强大的授权和认证功能,保护我们的数据资源免受未经授权的访问。这些功能可以通过简单的配置和自定义实现来满足不同应用程序的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值