4.2 JWT 的流程
4.3 JWT 代码案例
如果你们公司有第三方应用接入的开放平台,那可以在里面走相应的接入流程得到 appId 和 appSecret。如果没有的话,那可以简单点与第三方约定相应的 appId 和 appSecret。老周这里假设你们已经约定好了,我这里直接放在请求头里来获取 token,还有其它的方式,比如放在请求参数或者 cookie 里。
4.3.1 maven 依赖
com.auth0
java-jwt
3.4.1
4.3.2 JWTUtil 工具类
public class JWTUtil {
private static String SECRETE = “default_secrete”;
private static String APP_ID = “zhifubao”;
private static String APP_SECRETE = “123abc”;
/**
-
传入 appId、appSecret 进行验证
-
@param appId 应用id
-
@param appSecret 应用密钥
-
@return 返回一个加密 JWT token
*/
public static String getToken(String appId, String appSecret) {
String token = JWT.create()
// 存放 payload 数据
.withClaim(“appId”, appId)
.withClaim(“appSecret”, appSecret)
// 使用 SECRETE 对称加密生成 signature
.sign(Algorithm.HMAC256(SECRETE));
return token;
}
/**
-
验证 token
-
@param token
-
@return
*/
public static boolean verifyToken(String token) {
HashMap<String, String> map = new HashMap<>();
// 通过 SECRETE 和相同的对称加密算法反加密
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SECRETE))
.build().verify(token);
// 获得你储存的 payload 信息
String appId = jwt.getClaim(“appId”).asString();
String appSecret = jwt.getClaim(“appSecret”).asString();
if (APP_ID.equals(appId) && APP_SECRETE.equals(appSecret)) {
return true;
}
return false;
}
}
4.3.3 JWTController 类
@RestController
public class JWTController {
@RequestMapping(“/getToken”)
public String getToken(@RequestHeader(“appId”) String appId, @RequestHeader(“appSecret”) String appSecret) {
return JWTUtil.getToken(appId, appSecret);
}
}
4.3.4 测试
拓展:这个私钥 secrete 是固定的,为了加强安全,你甚至可以使用动态的 secrete 私钥,
例如:动态私钥 = 静态私钥 + 用户的 ip,这样即使别人得到了用户的 token,也会因为 ip 不一致而访问失败。
拿到了应用资源服务器的 token 令牌了,那我们拿这个令牌去访问相应的资源看看。
@RequestMapping(“/getResource”)
public String getResource(String resourceId) {
return resourceId + " 资源获取成功";
}
简单模拟一个请求,直接返回该资源获取成功。我们接下来就用 postman 工具来模拟一下这个资源服务器的这个接口请求。
认证失败了,这是因为我们没有在请求头里填刚刚获取的 token。我们把通过调用 getToken 接口获取的 token 值放在在请求头,然后认证通过,获取到了资源服务器的资源。
4.3.5 继续追问
这里你有可能问了,老周,这里咋就带上 token 在请求头就可以获取到了资源服务器的资源啊。
我把代码贴出来,你一看就知道了。
这里写了一个 token 的拦截器,对请求头的 token 进行验签,通过才放行。
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader(“token”);
if (token != null) {
boolean result = JWTUtil.verifyToken(token);
if (result) {
System.out.println(“通过拦截器”);
return true;
}
}
response.setCharacterEncoding(“UTF-8”);
response.setContentType(“application/json; charset=utf-8”);
try{
response.getWriter().append(“认证失败,无效的token令牌!”);
System.out.println(“认证失败,无效的token令牌!”);
} catch (Exception e) {
e.printStackTrace();
response.sendError(500);
return false;
}
return false;
}
}
这里有个拦截器配置类,把需要拦截的 api 路径放进来,然后会对某个 api 进行细粒度的管控。
@Configuration
public class IntercepterConfig implements WebMvcConfigurer {
private TokenInterceptor tokenInterceptor;
public IntercepterConfig(TokenInterceptor tokenInterceptor){
this.tokenInterceptor = tokenInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
List excludePath = new ArrayList<>();
excludePath.add(“/getResource/”);
excludePath.add(“/static/**”); //静态资源
registry.addInterceptor(tokenInterceptor)
.addPathPatterns(“/**”)
.excludePathPatterns(excludePath);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
这就实现中型网站安全认证机制了,细心的读者可能会发现,这个 token 是固定的,会存在一些不安全。是的,我上面也说了,可以用动态的 secrete 私钥或者 token 过期机制来继续保证更高的安全性。
大型网站的话,针对中型网站的方案就不太可行了,为什么呢?由于大型网站的请求流量很大,而 token 由于自包含信息,因此一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token 的签名验签操作也会给 cpu 带来额外的处理负担。可以采用微服务统一认证方案 Spring Cloud OAuth2,那什么情况下需要使用 OAuth2?
-
第三方授权登录
的场景:比如,我们经常登录一些网站或者应用的时候,可以选择使用第三方授权登录的方式,比如:微信授权登录、QQ授权登录、微博授权登录等,这是典型的 OAuth2 使用场景。 -
单点登录
的场景:如果项目中有很多微服务或者公司内部有很多服务,可以专⻔做一个认证中心(充当 认证平台⻆色),所有的服务都要到这个认证中心做认证,只做一次登录,就可以在多个授权范围内的服务中自由串行。
5.1 OAuth2 构建微服务统一认证服务思路
注意:在我们统一认证的场景中,Resource Server 其实就是我们的各种受保护的微服务,微服务中的 各种 API 访问接口就是资源,发起 http 请求的浏览器就是 Client 客户端(对应为第三方应用)。
5.1.1 搭建认证服务器(Authorization Server)
5.1.1.1 maven 依赖文件
5.1.1.2 application.yml 文件
5.1.1.3 OauthServerApplication9999 启动类
5.1.1.4 认证服务器配置类
5.1.1.5 认证服务器安全配置类
5.1.1.6 测试
5.1.1.6.1 获取 token
endpoint:/oauth/token
获取token携带的参数
client_id:客户端id
client_secret:客户单密码
grant_type:指定使用哪种颁发类型,password
username:用户名
password:密码
5.1.1.6.2 校验 token
http://localhost:9999/oauth/check_token?token=28317df7-4036-4bbb-8bb3-12f71fa07802
如果出现以上页面,表明 token 过期了,设置的是 20s。所以要在 20s 以内校验才会生效。
下面才是 token 校验成功的效果:
5.1.1.6.3 刷新 token
5.1.2 搭建资源服务器(希望访问被认证的微服务)
5.1.2.1 资源服务 Resource Server 配置类
5.1.2.2 测试
面试资料整理汇总
这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。
面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了
在这里祝大家能够拿到心仪的offer!
*
5.1.2.1 资源服务 Resource Server 配置类
5.1.2.2 测试
面试资料整理汇总
[外链图片转存中…(img-LowPex95-1720105548029)]
[外链图片转存中…(img-veiSJ55w-1720105548029)]
这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。
面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了
在这里祝大家能够拿到心仪的offer!