クロスドメイン認証が遭遇する問題の一つ
マルチ端末の出現に起因して、多くのサイトを通じてweb api restful
途中に基づく伝統的な認証に関連することができる分離の終わり頃開発されたモデルを使用して外部サービスの形、でクロスドメインの提出に向け以外に異なるアプローチ、問題の外、もっと重要なのは、いくつかの端末はサポートしていない可能性があります。cookie
Session Id
cookie
cookie
JWT(JSON Web Token)
認証および承認スキームは、単に通話が通話を終了することを意味しているapi
にはで来るときapi
、発行側token
、発信者の認証情報を検証するために、。
一般的なプロセスは以下です:
1. 用户向服务器发送用户名和密码。
2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
このモデルの問題は、貧しい人々スケーラビリティです。ユーザがサーバのクラスタ、クロスドメインサービス指向アーキテクチャーまたは無効になっている場合に単一の問題が、ありませんcookie
死にます、。
第二に、ソリューション
1.スタンドアロンおよびログインチェック、セッション共有に分散アプリケーション
シングルおよびマルチノード
tomcat
アプリケーションログオンテスト①は、スタンドアローンの
tomcat
アプリケーションのログインを、sesssion
ユーザーが正常にログインした後、ブラウザとアプリケーションサーバのセッションの間保存し、サーバーがあることを保証しますsession
クライアントの意志はsessionId
、クライアントがしますsessionId
保存しcookie
、ユーザーの要求はこれを運ぶたびに、sessionId
。②、マルチノード・
tomcat
アプリケーション、ログオン開くsession
データの共有を、各サーバが読み取ることができますsession
。欠点は、それぞれということであるsession
メモリとリソースを占有され、各サーバ・ノードは、ユーザが何百万レベルのリソースの占有量に達したとき、すなわち、各サーバにデータの複数のコピーを格納する必要があり、ユーザデータの同期を必要とそれは深刻で、ユーザ体験は特に悪いです!!分散アプリケーション
session
共有①、実際のアプリケーションは、単一ノードを展開することはできませんので、複数のノードのログインが存在する
session
共有解決すべき課題は。tomcat
サポートsession
の共有が、ブロードキャストストームがあり、ユーザーに多くの時間、リソースを大量に消費する深刻には、推奨されていません②、
Reids
クラスタ、ストレージ着陸token
外側にサービス・インターフェースは、Redis
(サーバを使用して有効期限を設定することができUUID
、ランダム生成する64
ビット又は128
ビットをtoken
、にRedis
し、クライアントに戻され、記憶されています)。③、ユーザーが正常にログオン初めて、あなたは自己生成する必要が
token
、その後、token
ブラウザに返され、保存されたcookie
中、
およびRedis
サーバー上token
などkey
などのユーザ情報value
保存します。その後のユーザ操作ができHttpServletRequest
、直接オブジェクトを読み出しcookie
ているtoken
、そしてRedis
(各時間は、ユーザがこのアクセスを運ぶの比較が行われ、対応するユーザデータを取得するためtoken
にサーバRedis
が存在するかどうかを確認するユーザー)。④、短所:展開する必要があり
Redis
、それぞれが訪問しなければならない、Redis
、IO
コストが特に大きいです。
2.最終的な解決方法:JWTはトークン認証を実現
JWT原則
認証サーバがユーザに戻って、ユーザーとサーバーの通信時間後にJSONオブジェクトを生成した後、我々はJSONオブジェクトを送り返す必要があります。サーバーは、完全にオブジェクト識別されたユーザに依存しています。オブジェクトを生成するとき、データの改ざんからユーザーを防止するために、サーバは、署名が追加されます。そのサーバーはすべてのセッションデータを保存しません、それは、サーバーがステートレス、および拡張を実現することが比較的容易になります。
简单来说,就是通过一定规范来生成 token,然后可以通过解密算法逆向解密 token,这样就可以获取用户信息
賛否両論
長所:生産トークンは、そのようなID、ユーザーのニックネーム、アバターやその他の情報など、基本的な情報が含まれている再を避けるために、ライブラリを確認することができ、サーバーのメモリリソースではなく、クライアントに保存されています
欠点:トークンはbase64エンコードした後、それを復号することができるので、暗号化前のオブジェクトトークンが機密情報を含んではならない(例えば、ユーザのアクセス権、パスワード、等)
ヘッド+負荷+署名(ヘッダ+ペイロード+署名):JWT形式は、から成り
ヘッド:主に署名アルゴリズムを記述します。
ロード:など、ユーザIDとして、暗号化されたオブジェクトの情報を記述し、また、ISS発行者、有効期限の経験、サブ指向のユーザーとして、仕様内のいくつかのものを追加することができます。
署名:主要部分は、トークンを改ざんベースを復号化することがトークンを取得するために他の人を防ぐために、最初の2つの暗号化です。
図3.ケースデザイン
第三に、コードは、ケースを示しています
そして導入pom.xmlファイル依存エンティティクラス
<!-- 依赖可以减少实体类 getter/setter等方法书写 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- JWT相关 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> ==================================================================================== @Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor public class User implements Serializable { private Integer id; private String openid; private String name; private String headImg; private String phone; private String sign; private Integer sex; private String city; private Date createTime; }
JWT生成ツール
public class JwtUtil { // 主题 public static final String SUBJECT = "RookieLi"; // 秘钥 public static final String SECRETKEY = "Rookie666"; // 过期时间 public static final long EXPIRE = 1000 * 60 * 60 * 24 * 7; //过期时间,毫秒,一周 // 生成 JWT public static String geneJsonWebToken(User user) { if (user == null || user.getId() == null || user.getName() == null || user.getHeadImg() == null) { return null; } String token = Jwts.builder() .setSubject(SUBJECT) .claim("id", user.getId()) .claim("name", user.getName()) .claim("img", user.getHeadImg()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) .signWith(SignatureAlgorithm.HS256, SECRETKEY).compact(); return token; } // 校验 JWT public static Claims checkJWT(String token) { try { final Claims claims = Jwts.parser().setSigningKey(SECRETKEY). parseClaimsJws(token).getBody(); return claims; } catch (Exception e) { e.printStackTrace(); } return null; } }
JWTのテストツール
public class JwtUtilTest { @Test public void testGeneJwt(){ User user = new User(); user.setId(999); user.setHeadImg("I'm busy"); user.setName("Rookie"); String token = JwtUtil.geneJsonWebToken(user); System.out.println(token); } @Test public void testCheck(){ // 下面此 token 字符串是上面的结果生成的,每次不一样,不是写死的 String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJSb29raWVMaSIsImlkIjo5OTksIm5hbWUiOiJSb29raWUiLCJpbWciOiJJJ20gYnVzeSIsImlhdCI6MTU2NzMxNjk4NywiZXhwIjoxNTY3OTIxNzg3fQ.FJh41VwVh2gh5-_cOG0SOgoO3dR_ZcK9VWNNskWqKl0"; Claims claims = JwtUtil.checkJWT(token); if(claims != null){ String name = (String)claims.get("name"); String img = (String)claims.get("img"); int id =(Integer) claims.get("id"); System.out.println(name); System.out.println(img); System.out.println(id); }else{ System.out.println("非法token"); } } }
参考ブログ:
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
https://www.cnblogs.com/jpfss/p/10929458.html