本次主要是用来记录,使用springboot,Oauth2.0,jwt令牌的一些基本知识,以及利用以上几乎来实现单点登录,权限控制等功能的基本流程。

1.授权流程

本次授权流程如下图所示,采用私钥签名,公钥校验的方式来校验token令牌。

2.公钥私钥

Spring Security 提供对JWT的支持,本节我们使用Spring Security 提供的JwtHelper来创建JWT令牌,校验JWT令牌 等操作。 这里JWT令牌我们采用非对称算法进行加密,所以我们要先生成公钥和私钥。

(1)生成密钥证书 下边命令生成密钥证书,采用RSA 算法每个证书包含公钥和私钥

创建一个文件夹,在该文件夹下执行如下命令行:

keytool -genkeypair -alias changgou -keyalg RSA -keypass changgou -keystore changgou.jks -storepass changgou

Keytool 是一个java提供的证书管理工具

-alias:密钥的别名
-keyalg:使用的hash算法
-keypass:密钥的访问密码
-keystore:密钥库文件名,xc.keystore保存了生成的证书
-storepass:密钥库的访问密码

(2)查询证书信息

keytool -list -keystore changgou.jks

(3)删除别名

keytool -delete -alias changgou -keystore changgou.jsk

4.2.3 导出公钥

openssl是一个加解密工具包,这里使用openssl来导出公钥信息。

安装 openssl:http://slproweb.com/products/Win32OpenSSL.html

安装资料目录下的Win64OpenSSL-1_1_0g.exe

配置openssl的path环境变量

cmd进入changgou.jks文件所在目录执行如下命令(如下命令在windows下执行,会把-变成中文方式,请将它改成英文的-):

keytool -list -rfc --keystore changgou.jks | openssl x509 -inform pem -pubkey

下面段内容是公钥

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvFsEiaLvij9C1Mz+oyAm
t47whAaRkRu/8kePM+X8760UGU0RMwGti6Z9y3LQ0RvK6I0brXmbGB/RsN38PVnh
cP8ZfxGUH26kX0RK+tlrxcrG+HkPYOH4XPAL8Q1lu1n9x3tLcIPxq8ZZtuIyKYEm
oLKyMsvTviG5flTpDprT25unWgE4md1kthRWXOnfWHATVY7Y/r4obiOL1mS5bEa/
iNKotQNnvIAKtjBM4RlIDWMa6dmz+lHtLtqDD2LF1qwoiSIHI75LQZ/CNYaHCfZS
xtOydpNKq8eb1/PGiLNolD4La2zf0/1dlcr5mkesV570NxRmU1tFm8Zd3MZlZmyv
9QIDAQAB
-----END PUBLIC KEY-----

将上边的公钥拷贝到文本public.key文件中,合并为一行,可以将它放到需要实现授权认证的工程中。

3.创建jwt令牌

(1)创建令牌数据

在changgou-user-oauth工程中创建测试类com.changgou.token.CreateJwtTest,使用它来创建令牌信息,代码如下:

    public class CreateJwtTest {/**** 创建令牌测试*/@Testpublic void testCreateToken(){//证书文件路径String key_location="changgou.jks";//秘钥库密码String key_password="changgou";//秘钥密码String keypwd = "changgou";//秘钥别名String alias = "changgou";//访问证书路径ClassPathResource resource = new ClassPathResource(key_location);//创建秘钥工厂KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource,key_password.toCharArray());//读取秘钥对(公钥、私钥)KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias,keypwd.toCharArray());//获取私钥RSAPrivateKey rsaPrivate = (RSAPrivateKey) keyPair.getPrivate();//定义PayloadMap<String, Object> tokenMap = new HashMap<>();tokenMap.put("id", "1");tokenMap.put("name", "itheima");tokenMap.put("roles", "ROLE_VIP,ROLE_USER");//生成Jwt令牌Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner(rsaPrivate));//取出令牌String encoded = jwt.getEncoded();System.out.println(encoded);}}

运行后的结果如下:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6IlJPTEVfVklQLFJPTEVfVVNFUiIsIm5hbWUiOiJpdGhlaW1hIiwiaWQiOiIxIn0.IR9Qu9ZqYZ2gU2qgAziyT38UhEeL4Oi69ko-dzC_P9-Vjz40hwZDqxl8wZ-W2WAw1eWGIHV1EYDjg0-eilogJZ5UikyWw1bewXCpvlM-ZRtYQQqHFTlfDiVcFetyTayaskwa-x_BVS4pTWAskiaIKbKR4KcME2E5o1rEek-3YPkqAiZ6WP1UOmpaCJDaaFSdninqG0gzSCuGvLuG40x0Ngpfk7mPOecsIi5cbJElpdYUsCr9oXc53ROyfvYpHjzV7c2D5eIZu3leUPXRvvVAPJFEcSBiisxUSEeiGpmuQhaFZd1g-yJ1WQrixFvehMeLX2XU6W1nlL5ARTpQf_Jjiw

(2)解析令牌

上面创建令牌后,我们可以对JWT令牌进行解析,这里解析需要用到公钥,我们可以将之前生成的公钥public.key拷贝出来用字符串变量token存储,然后通过公钥解密。

在changgou-user-oauth创建测试类com.changgou.token.ParseJwtTest实现解析校验令牌数据,代码如下:

public class ParseJwtTest {/**** 校验令牌*/@Testpublic void testParseToken(){//令牌String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6IlJPTEVfVklQLFJPTEVfVVNFUiIsIm5hbWUiOiJpdGhlaW1hIiwiaWQiOiIxIn0.IR9Qu9ZqYZ2gU2qgAziyT38UhEeL4Oi69ko-dzC_P9-Vjz40hwZDqxl8wZ-W2WAw1eWGIHV1EYDjg0-eilogJZ5UikyWw1bewXCpvlM-ZRtYQQqHFTlfDiVcFetyTayaskwa-x_BVS4pTWAskiaIKbKR4KcME2E5o1rEek-3YPkqAiZ6WP1UOmpaCJDaaFSdninqG0gzSCuGvLuG40x0Ngpfk7mPOecsIi5cbJElpdYUsCr9oXc53ROyfvYpHjzV7c2D5eIZu3leUPXRvvVAPJFEcSBiisxUSEeiGpmuQhaFZd1g-yJ1WQrixFvehMeLX2XU6W1nlL5ARTpQf_Jjiw";//公钥String publickey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvFsEiaLvij9C1Mz+oyAmt47whAaRkRu/8kePM+X8760UGU0RMwGti6Z9y3LQ0RvK6I0brXmbGB/RsN38PVnhcP8ZfxGUH26kX0RK+tlrxcrG+HkPYOH4XPAL8Q1lu1n9x3tLcIPxq8ZZtuIyKYEmoLKyMsvTviG5flTpDprT25unWgE4md1kthRWXOnfWHATVY7Y/r4obiOL1mS5bEa/iNKotQNnvIAKtjBM4RlIDWMa6dmz+lHtLtqDD2LF1qwoiSIHI75LQZ/CNYaHCfZSxtOydpNKq8eb1/PGiLNolD4La2zf0/1dlcr5mkesV570NxRmU1tFm8Zd3MZlZmyv9QIDAQAB-----END PUBLIC KEY-----";//校验JwtJwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publickey));//获取Jwt原始内容String claims = jwt.getClaims();System.out.println(claims);//jwt令牌String encoded = jwt.getEncoded();System.out.println(encoded);}}

运行后的结果如下:
![

在这里插入图片描述

](https://img-blog.csdnimg.cn/20200529054527527.png)

4.Oauth微服务开发

  1. controller层提供了一个认证接口/user/login
@RestController
@RequestMapping("/user")
public class AuthController {@AutowiredAuthService authService;@Value("${auth.clientId}")private String clientId;@Value("${auth.clientSecret}")private String clientSecret;@Value("${auth.cookieDomain}")private String cookieDomain;@Value("${auth.cookieMaxAge}")private int cookieMaxAge;@RequestMapping("/login")public Result login(String username, String password, HttpServletResponse response){if(StringUtils.isEmpty(username)){throw new RuntimeException("用户名不允许为空");}if(StringUtils.isEmpty(password)){throw new RuntimeException("密码不允许为空");}AuthToken authToken = authService.login(username, password, clientId, clientSecret);String accessToken = authToken.getAccessToken();CookieUtil.addCookie(response,cookieDomain,"/","Authorization",accessToken,cookieMaxAge,false);return new Result(true, StatusCode.OK,"登录成功");}
}
  1. service层实现
@Service
public class AuthServiceImpl implements AuthService {@AutowiredRestTemplate restTemplate;@AutowiredLoadBalancerClient loadBalancerClient;/*** 密码登录模式* @param username      用户名* @param password      用户密码* @param clientId      客户端id* @param clientSecret  客户端密钥* @return*/@Overridepublic AuthToken login(String username, String password, String clientId, String clientSecret) {//获取请求地址   http://localhost:9001/oauth/token//选中认证服务的地址ServiceInstance serviceInstance = loadBalancerClient.choose("user-auth");if(serviceInstance==null){throw new RuntimeException("找不到对应的微服务");}//获取令牌的urlString path = serviceInstance.getUri().toString() + "/oauth/token";//定义bodyMultiValueMap<String, String> bodyMap = new LinkedMultiValueMap<>();bodyMap.add("grant_type","password");bodyMap.add("username",username);bodyMap.add("password",password);//定义头MultiValueMap<String, String> headerMap = new LinkedMultiValueMap<>();//头格式为Basic +//               clientId:clientSecret的Base65转码后的结果String string = clientId+":"+clientSecret;byte[] encode = Base64Utils.encode(string.getBytes());String headerStr = "Basic "+new String(encode);headerMap.add("Authorization",headerStr);restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {@Overridepublic void handleError(ClientHttpResponse response) throws IOException {//当响应的值为400或401时候也要正常响应,不要抛出异常if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) {super.handleError(response);}}});//向服务端发送请求//http请求spring security的申请令牌接口Map map=null;ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,new HttpEntity<MultiValueMap<String, String>>(bodyMap, headerMap), Map.class);map = mapResponseEntity.getBody();if(map==null || map.get("access_token")==null || map.get("refresh_token")==null || map.get("jti")==null){throw new RuntimeException("创建令牌失败");}AuthToken authToken = new AuthToken();authToken.setAccessToken(map.get("access_token").toString());authToken.setRefreshToken(map.get("refresh_token").toString());authToken.setJti(map.get("jti").toString());return authToken;}
  1. SpringSecurityOauth的一些其他配置,此处省略

5.oauth2.0微服务之间的认证

1.认证流程

1.用户在访问oauth微服务时,比如说在进行登录时,肯定会访问user微服务,调用findByUserId方法查询用户名是否存在
2.这时候就会存在一个微服务之间的认证问题,user微服务会校验oauth微服务的feign调用是否还有token,以及token的格式,权限,但是用户此时还未登录没有token令牌
3.由于是自己系统内部的微服务互相调用,此时可以设置一个feign调用拦截器,手动生成一个token,设置权限为admin后,在进行feign调用
4.user微服务收到请求后,校验token,根据id查询对应的用户信息并返回。
5.若是访问其他微服务,如果用户已登录,直接在feign调用之前获取请求头文件,将其中的内容存到requestTemplate的头文件中去

2.详细步骤

1.登录请求

  1. 定义一个拦截器
    在项目目录下创建interceptor包,并创建OauthInterceptor类
   public class OauthInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {AdminToken adminToken = new AdminToken();String token = "bearer "+adminToken.createAdminToken();requestTemplate.header("Authorization",token);}
}

2.当中的AdminToken是一个工具类,专门为访问user微服务远程调用时,因为是登录操作,还没有携带token,又需要根据用户名查询用户信息,所以手动创建一个token,存入到头文件中
代码如下:

public String createAdminToken(){//证书文件路径String key_location="changgou.jks";//密钥库密码String key_password="changgou";//密钥密码String keypwd = "changgou";//密钥别名String alias = "changgou";//加载证书文件ClassPathResource resource = new ClassPathResource(key_location);//根据证书文件创建密钥工厂KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, key_password.toCharArray());//读取密钥对(公钥,私钥)KeyPair keyPair = keyStoreKeyFactory.getKeyPair("changgou");//获取私钥RSAPrivateKey rasPrivate = (RSAPrivateKey) keyPair.getPrivate();//定义payload(载荷)HashMap<String, Object> tokenMap = new HashMap<>();tokenMap.put("id",1);tokenMap.put("name","itheima");//登录调用是内部调用,直接给与admin泉休闲tokenMap.put("authorities",new String[]{"admin","oauth"});//生成Jwt令牌Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner(rasPrivate));//取出令牌String encoded = jwt.getEncoded();//System.out.println(encoded);return encoded;}

2.其他请求

拦截器内容如下:

public class FeignInterceptor implements RequestInterceptor{/*** 每次微服务调用之前,都先检查头文件* 并将头文件中的令牌数据,存放到header中* @param requestTemplate*/@Overridepublic void apply(RequestTemplate requestTemplate) {//使用RequestContextHolder工具获取request相关变量ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//判断是否为空if(attributes!=null){Enumeration<String> headerNames = attributes.getRequest().getHeaderNames();if(headerNames!=null){while (headerNames.hasMoreElements()){String headerName = headerNames.nextElement();String values = attributes.getRequest().getHeader(headerName);requestTemplate.header(headerName,values);}}}//遍历,加入到新的header中}
}

其他操作类似
详情见本地文档

使用springboot,Oauth2.0,jwt令牌实现单点登录,权限控制等功能的基本流程相关推荐

  1. SpringBoot OAuth2.0 使用短信验证码登录授权

    SpringBoot OAuth2.0 使用短信验证码登录授权 实现步骤: 自定义授权器,继承 AbstractTokenGranter 类: 重写 getOAuth2Authentication 函 ...

  2. JWT实战 Spring Security Oauth2整合JWT 整合SSO单点登录

    文章目录 一.JWT 1.1 什么是JWT 1.2 JWT组成 头部(header) 载荷(payload) 签名(signature) 如何应用 1.3 JJWT 快速开始 创建token toke ...

  3. SpringSecurity+OAuth2.0+JWT实现单点登录应用

    SpringSecurity+OAuth2.0+JWT实现单点登录应用 gitee项目练习地址:https://gitee.com/xzq25_com/springsecurity.oauth2 OA ...

  4. oauth2.0+jwt资源服务器配置

    oauth2.0+jwt资源服务的配置 配置ResourceConfig 测试 密码授权方式 授权码方式 配置ResourceConfig package com.fxj.resource.confi ...

  5. Spring Security整合JWT,实现单点登录,So Easy~!

    前面整理过一篇 SpringBoot Security前后端分离,登录退出等返回json数据,也就是用Spring Security,基于SpringBoot2.1.4 RELEASE前后端分离的情况 ...

  6. C#session共享+redis_技术干货分享:基于SpringBoot+Redis的Session共享与单点登录

    categories: 架构 author: mrzhou tags: SpringBoot redis session 单点登录 基于SpringBoot+Redis的Session共享与单点登录 ...

  7. CodeArt WSS3.0(MOSS)字段编辑权限控制解决方案(v1.0)

    Windows SharePint Service 3.0(或MOSS)默认不支持字段级的权限.而在项目的实施过程中,客户经常会提出这个需求. 解决方案有两种: 1)开发自定义的字段,在字段上附加控制 ...

  8. java B2B2C Springboot电子商务平台源码-SSO单点登录之OAuth2.0登录认证

    之前写了很多关于spring cloud的文章,今天我们对OAuth2.0的整合方式做一下笔记,首先我从网上找了一些关于OAuth2.0的一些基础知识点,帮助大家回顾一下知识点: 一.oauth中的角 ...

  9. SpringBoot+SpringSecurity+JWT整合实现单点登录SSO史上最全详解

    作者:波波烤鸭 blog.csdn.net/qq_38526573/article/details/103409430 一.什么是单点登陆 单点登录(Single Sign On),简称为 SSO,是 ...

  10. springboot+vue jwt校验token 单点登录

    SSO(Single Sign On)模式 CAS单点登录.OAuth2 分布式,SSO(single sign on)模式:单点登录英文全称Single Sign On,简称就是SSO.它的解释是: ...

最新文章

  1. 简单介绍互联网领域选择与营销方法
  2. mysql基础搭建_MySql基础-构建MySql数据库:安装MySql-server、MySql-client
  3. 深度学习课程Deep Learning Courses
  4. 【AI白身境】Linux干活三板斧,shell、vim和git
  5. SpringBoot整合MQTT服务器实现消息的发送与订阅(推送消息与接收推送)
  6. memcached协议
  7. Android ADB
  8. 快手:笔试题(版本号比较,平方和为1,合并两个流)
  9. 利用递归遍历文件夹和文件存入TreeView
  10. tiktok跨境出海?
  11. oracle安装无响应,求教 pl/sql连接本机数据库是未响应问题
  12. 基于 RK3399 5G 通信和图像增强算法的交通监控系统设计
  13. 阿里巴巴官方:明年今日马云将不再担任董事局主席
  14. PS图层蒙版应用——图片抠字
  15. app注册协议通用模版
  16. 干货 | 携程机票Sketch插件开发实践
  17. FileZilla远程上传文件失败原因和解决办法
  18. nginx error_log 日志配置
  19. 结合CAP理论分析ElasticSearch的分布式实现方式
  20. 【SCI征稿】大数据类SCI,走期刊部系统,正刊,审稿顺利

热门文章

  1. php 批量 挂马,php下批量挂马和批量清马代码
  2. Windows高效文件搜索工具/Everything/Listary/uTools
  3. ai杀手级_设计师的10个杀手级Adobe Photoshop技巧
  4. Beamer中数学符号字体
  5. 抖音直播睡觉一晚赚7.6万,心态崩了
  6. jersey restful 测试_Jersey 开发RESTful(七)Jersey快速入门
  7. 增强版在线LEFSe分析和可视化鉴定标志性基因或物种
  8. 三十岁左右的你,现在收入多少?
  9. 三阶魔方大中小魔公式_三阶魔方花样玩法,公式汇总
  10. 指针变量与数组的关系及什么是指针数组