1. JWT とは
JSON Web トークン (JWT) は、現在最も人気のあるクロスドメイン認証ソリューションです。現在のプロジェクト開発では一般的にフロントエンドとエンドエンドの分離が行われており、これにはクロスドメインと認証の問題が伴います。
2. JWT の構成
ヘッダー、ペイロード、署名の 3 つの部分で構成されます
Header :
ヘッダー情報1. トークンのタイプ、つまり JWT; 2. 使用される署名アルゴリズム (HMASSHA256 や RSA など);
{ "alg": "HS256", "typ": "JWT" }
この json では、typ 属性は、トークン全体がトークンであることを識別するために使用されます。トークン文字列は JWT 文字列です。その alg 属性は、この JWT を発行するときに使用される署名およびダイジェスト アルゴリズムを記述するために使用されます。typ 属性と alg 属性の完全な名前は、実際にはそれぞれ type アルゴリズムです。タイプとアルゴリズムの意味。 3文字で表す理由も、JWTの最終的な文字列サイズを考慮したもので、JWTの名前とも整合性があるため、すべて3文字で …typとalgは、で指定する属性です。 JWT 標準の名前。
ペイロード:
ペイロードは、送信されるデータを運ぶために使用されます。その json 構造は、実際には、JWT によって送信されるデータの宣言のセットです。 JWT 標準ではステートメントはクレームと呼ばれます。その「属性値ペア」の 1 つが実際にはクレーム (要件) であり、各クレームは特定の意味と機能を表します。
クレームにビジネス情報を含めることができます。
署名:
署名は、ヘッダーとペイロードに対応する JSON 構造を Base64URL でエンコードし、「英語のピリオド」で結合した後に得られる 2 つの文字列です。その後、ヘッダーの alg で指定された署名アルゴリズムに従って生成されます。
アルゴリズムが異なれば、署名結果も異なります。 alg: HS256 を例として、前の署名を取得する方法を説明します。
alg の利用可能な値に関する前述の説明によると、HS256 には実際には HMAC アルゴリズムと SHA256 アルゴリズムの 2 つのアルゴリズムが含まれています。前者はダイジェストの生成に使用され、後者はダイジェストのデジタル署名に使用されます。ダイジェスト。これら 2 つのアルゴリズムは、HMACSHA256
jwt データ構造図:
3. JWT の動作原理
1 と総称されることもあります。ログイン リクエストが送信されると、必然的にユーザー情報 uname と pwd
2 が送信されます。ユーザー情報 uname と pwd が正常にログインすると、ユーザー情報は jwt ツールを通じて暗号化された文字列に生成されます。 class
3. 暗号化された文字列は、応答ヘッダーの形式でフロントエンドに送信されます
#4. フロントエンド サーバーには、伝送される jwt 文字列をインターセプトするための応答インターセプターがあります。応答ヘッダーによって、それを Vuex5 に追加します。2 回目のリクエスト時には、フロントエンド サーバーにリクエスト インターセプターがあり、Vuex の jwt 文字列をリクエスト ヘッダー request # に追加します。##6. リクエストがクロスドメイン メソッドを通過してバックエンド サーバーに到達すると、バックエンド サーバーに別のフィルターがあり、リクエスト ヘッダーの jwt 文字列をインターセプトします。 jwt ツール クラスは、jwt 文字列を解析し、それをユーザー情報に解析し、最終的に検証します。バックグラウンド ログイン インターフェイスにアクセスしてログインします。最初にユーザー名とパスワードに基づいてユーザー テーブルにユーザーが存在するかどうかが判断されます。存在する場合、このユーザーに対して jwt 文字列が生成されます。jwt にビジネス情報を追加できます。文字列 (ログイン アカウント、ユーザーの本名など) を取得し、jwt 文字列をフロントエンドに返します。
現在のエンドは jwt 文字列を取得し、それをすべてのリクエストのヘッダーに挿入します。 as token=jwt string
すべてのリクエスト (ログインリクエストはまだ jwt を生成していないため、ログインリクエストを除く) をインターセプトするフィルターをバックエンドで開発し、リクエストのヘッダーから jwt を取得します (つまり、 、トークンの値)、jwt を確認して jwt 内のビジネス情報を取得し、バックエンド インターフェイスがヘッダーから直接ビジネス情報を取得できるように、リクエストのヘッダーにビジネス情報を置きます
フィルターの場合 jwt の有効期限が切れるか検証が失敗した場合、プロンプトがフロントエンドに返され、フロントエンドはログイン ページに戻ってユーザーが再度ログインできるようにします。
1. pom.xml に依存関係を導入します
<!--jwt--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.8.3</version> </dependency>
2. jwt 生成ツール クラスを開発します。コードは次のとおりです:
package com.lsl.exam.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.lsl.exam.entity.TabUser; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JwtUtil { private static final long EXPIRE_TIME = 1000 * 60 * 60 *24; //设置私钥 private static final String TOKEN_SECRET = "aa082c-66rt89-29sr3t-y9t7b8"; /** * 创建携带自定义信息和声明的自定义私钥的jwt * @param user 用户信息表 * @return jwt串 */ public static String creatJwt(TabUser user){ //构建头部信息 Map<String,Object> header = new HashMap<>(); header.put("typ","JWT"); header.put("alg","HS256"); //根据私钥构建密钥信息 Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); //根据当前用户密码构建密钥信息 // Algorithm algorithm = Algorithm.HMAC256(user.getUserpwd()); //设置过期时间为当前时间一天后 Date nowDate = new Date(); Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME); String jwt = JWT.create().withHeader(header) .withClaim("account",user.getAccount())//业务信息:员工号 .withClaim("username",user.getUsername())//业务信息:员工姓名 .withClaim("rolename",user.getRoleName())//业务信息:角色 .withIssuer("SERVICE")//声明,签名是有谁生成 例如 服务器 .withNotBefore(new Date())//声明,定义在什么时间之前,该jwt都是不可用的 .withExpiresAt(expireDate)//声明, 签名过期的时间 .sign(algorithm);//根据algorithm生成签名 return jwt; } }
3. バックエンド ログイン インターフェイスロジックは次のとおりです:
package com.lsl.exam.controller; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.lsl.exam.entity.TabUser; import com.lsl.exam.entity.backresult.ResultVO; import com.lsl.exam.service.ITabRoleService; import com.lsl.exam.service.IUserService; import com.lsl.exam.utils.Base64Util; import com.lsl.exam.utils.JwtUtil; import com.lsl.exam.utils.ResultVoUtil; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("/exam") public class UserController { private static final Logger LOG = org.slf4j.LoggerFactory.getLogger("UserController"); @Autowired IUserService userService; @Autowired ITabRoleService roleService; @PostMapping(value = "login",produces = "application/json;charset=UTF-8") @ResponseBody public ResultVO<?> login(@RequestBody Map params){ Map reuslt = new HashMap(); String account = params.get("account") == null ? "" : params.get("account").toString(); String pwd = params.get("pwd") == null ? "" : params.get("pwd").toString(); if ("".equals(account) || "".equals(pwd)){ return ResultVoUtil.error(30000,"用户名或者密码不能为空!"); } //pwd解密 String decodePwd = Base64Util.decode(pwd); if ("".contains(decodePwd)){ return ResultVoUtil.error(30000,"密码错误!"); } TabUser user = userService.getOne(new QueryWrapper<TabUser>() .eq("account",account) .eq("userpwd",decodePwd)); if (null == user){ return ResultVoUtil.error(30000,"用户名或者密码错误"); } //获取当前用户拥有的角色 String userId = user.getId(); Map roleMap = new HashMap(); roleMap.put("userId",userId); List<Map> roleList = roleService.qryRoleInfoByUserId(roleMap); List<String> roleNames = new ArrayList<>(); for(Map role : roleList){ roleNames.add(role.get("role").toString()); } user.setRoleName(JSON.toJSONString(roleNames)); //生成带有业务信息的jwt串 String jwt = JwtUtil.creatJwt(user); //把jwt和当前用户信息返给前端 reuslt.put("jwt",jwt); reuslt.put("roleNames",roleNames); reuslt.put("username",user.getUsername()); reuslt.put("account",user.getAccount()); return ResultVoUtil.success(reuslt); } @PostMapping(value = "qryUser",produces = "application/json;charset=UTF-8") @ResponseBody public Object qryUser(HttpServletRequest request){ //这里header中的信息是filter中放进去的 String account = request.getHeader("account"); String username = request.getHeader("username"); String rolename = request.getHeader("rolename"); List<TabUser> list = userService.list(); return ResultVoUtil.success(list); } }
4. フィルターを開発し、JWT 検証を実行します
package com.lsl.exam.filter; import com.alibaba.fastjson.JSON; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import com.lsl.exam.entity.backresult.ResultVO; import com.lsl.exam.utils.ResultVoUtil; import org.apache.tomcat.util.http.MimeHeaders; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * jwt校验过滤器 */ @Component @WebFilter(filterName = "jwtFilter",urlPatterns = {"/*"}) public class AuthJwtFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; String url = httpServletRequest.getRequestURL().toString(); //配置不进行jwt校验的请求路径 List<String> urlList = new ArrayList<>(); urlList.add("/exam/login"); boolean flag = false; for (String strUrl : urlList){ if (url.contains(strUrl)){ flag = true; } } try { if (!flag){ String token = httpServletRequest.getHeader("token"); //校验token,jwt过期有jwt自行校验,如果超时了,会执行catch里代码 DecodedJWT decodeJwt = JWT.require(Algorithm.HMAC256("aa082c-66rt89-29sr3t-y9t7b8")).build().verify(token); //获取jwt中的业务信息 String account = decodeJwt.getClaim("account").asString(); String username = decodeJwt.getClaim("username").asString(); String rolename = decodeJwt.getClaim("rolename").asString(); Map<String, String> headerMap = new HashMap<>(); headerMap.put("account",account); headerMap.put("username",username); headerMap.put("rolename",rolename); //把业务信息添加到request的header addHeader(httpServletRequest,headerMap); // Class<?> superclass = servletRequest.getClass().getSuperclass().getSuperclass(); // Field requestField = superclass.getDeclaredField("request"); // requestField.setAccessible(true); // RequestFacade requestFacadeInstance = (RequestFacade) requestField.get(servletRequest); RequestFacade requestFacadeInstance = (RequestFacade)superclass3; // Field requestField1 = requestFacadeInstance.getClass().getDeclaredField("request"); // requestField1.setAccessible(true); // Object requestInstance = requestField1.get(requestFacadeInstance); // Field coyoteRequestField = requestInstance.getClass().getDeclaredField("coyoteRequest"); // coyoteRequestField.setAccessible(true); // // Object coyoRequestInstance = requestField1.get(requestInstance); // Field headersField = coyoRequestInstance.getClass().getDeclaredField("headers"); // headersField.setAccessible(true); // // MimeHeaders headers = (MimeHeaders) headersField.get(coyoRequestInstance); // headers.removeHeader("token"); // headers.addValue("account").setString(account); // headers.addValue("username").setString(username); // headers.addValue("roleid").setString(roleid); // } } catch (Exception e) { //jwt校验失败,返给前端的code=1,前端要重定向到登录页面 PrintWriter writer = null; servletResponse.setCharacterEncoding("UTF-8"); servletResponse.setContentType("text/html; charset=utf-8"); try { writer = servletResponse.getWriter(); ResultVO vo = ResultVoUtil.successLogout(); String msg = JSON.toJSONString(vo); writer.println(msg); } catch (IOException ex) { } finally { if (writer != null){ writer.close(); } return; } } filterChain.doFilter(servletRequest,servletResponse); } /** * 向request的header中放业务信息 * @param request * @param headerMap */ private void addHeader(HttpServletRequest request, Map<String, String> headerMap) { if (headerMap==null||headerMap.isEmpty()){ return; } Class<? extends HttpServletRequest> c=request.getClass(); //System.out.println(c.getName()); System.out.println("request实现类="+c.getName()); try{ Field requestField=c.getDeclaredField("request"); requestField.setAccessible(true); Object o=requestField.get(request); Field coyoteRequest=o.getClass().getDeclaredField("coyoteRequest"); coyoteRequest.setAccessible(true); Object o2=coyoteRequest.get(o); System.out.println("coyoteRequest实现类="+o2.getClass().getName()); Field headers=o2.getClass().getDeclaredField("headers"); headers.setAccessible(true); MimeHeaders mimeHeaders=(MimeHeaders) headers.get(o2); for (Map.Entry<String,String> entry:headerMap.entrySet()){ mimeHeaders.removeHeader(entry.getKey()); mimeHeaders.addValue(entry.getKey()).setString(entry.getValue()); } }catch (Exception e){ e.printStackTrace(); } } @Override public void destroy() { } }
以上がSpringboot は JWT をどのように統合して ID 認証を実現しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

この記事では、分散アプリケーションを構築するためのJavaのリモートメソッドの呼び出し(RMI)について説明します。 インターフェイスの定義、実装、レジストリのセットアップ、およびクライアント側の呼び出しを詳述し、ネットワークの問題やセキュリティなどの課題に対処します。

この記事では、ネットワーク通信のためのJavaのソケットAPI、クライアントサーバーのセットアップ、データ処理、リソース管理、エラー処理、セキュリティなどの重要な考慮事項をカバーしています。 また、パフォーマンスの最適化手法も調査します

この記事では、カスタムJavaネットワーキングプロトコルの作成を詳述しています。 プロトコルの定義(データ構造、フレーミング、エラー処理、バージョン化)、実装(ソケットを使用)、データシリアル化、およびベストプラクティス(効率、セキュリティ、メンテナ


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

メモ帳++7.3.1
使いやすく無料のコードエディター

ドリームウィーバー CS6
ビジュアル Web 開発ツール

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

ホットトピック



