{"id":506,"date":"2025-03-09T01:25:59","date_gmt":"2025-03-08T17:25:59","guid":{"rendered":"https:\/\/www.ooboou.com\/?p=506"},"modified":"2025-03-10T23:28:24","modified_gmt":"2025-03-10T15:28:24","slug":"shiro%e6%9d%83%e9%99%90%e6%a1%86%e6%9e%b6","status":"publish","type":"post","link":"http:\/\/www.ooboou.com\/?p=506","title":{"rendered":"shiro\u6743\u9650\u6846\u67b6"},"content":{"rendered":"<h2>\u77e5\u8bc6\u70b9<\/h2>\n<pre><code class=\"line-numbers\">1\u3001\u6743\u9650\u7cfb\u7edf\u7684\u6574\u4f53\u6982\u5ff5\n2\u3001shiro\u6743\u9650\u6846\u67b6\u7684\u6838\u5fc3\u7ec4\u4ef6\n3\u3001springboot\u4e0bshiro\u7684\u4f7f\u7528\n4\u3001shiro\u8ba4\u8bc1\u9274\u6743\u7684\u7f13\u5b58\u673a\u5236\n5\u3001\u5206\u5e03\u5f0f\u4e0b\u4f7f\u7528shrio\u5904\u7406\u7edf\u4e00\u4f1a\u8bdd\n6\u3001\u5bc6\u7801\u91cd\u8bd5\u6b21\u6570\uff0c\u5e76\u53d1\u767b\u5f55\u63a7\u5236\n7\u3001\u524d\u540e\u7aef\u5206\u79bb\u7684\u9274\u6743\u65b9\u5f0f\n8\u3001\u5efa\u7acb\u5206\u5e03\u5f0f\u7edf\u4e00\u9274\u6743\u7cfb\u7edf\n<\/code><\/pre>\n<h2>\u7b2c\u4e00\u7ae0  \u6743\u9650\u6982\u8ff0<\/h2>\n<h3>1\u3001\u4ec0\u4e48\u662f\u6743\u9650<\/h3>\n<p>\u200b       \u6743\u9650\u7ba1\u7406\uff0c\u4e00\u822c\u6307\u6839\u636e\u7cfb\u7edf\u8bbe\u7f6e\u7684\u5b89\u5168\u7b56\u7565\u6216\u8005\u5b89\u5168\u89c4\u5219\uff0c\u7528\u6237\u53ef\u4ee5\u8bbf\u95ee\u800c\u4e14\u53ea\u80fd\u8bbf\u95ee\u81ea\u5df1\u88ab\u6388\u6743\u7684\u8d44\u6e90\uff0c\u4e0d\u591a\u4e0d\u5c11\u3002\u6743\u9650\u7ba1\u7406\u51e0\u4e4e\u51fa\u73b0\u5728\u4efb\u4f55\u7cfb\u7edf\u91cc\u9762\uff0c\u53ea\u8981\u6709\u7528\u6237\u548c\u5bc6\u7801\u7684\u7cfb\u7edf\u3002<\/p>\n<p>\u6743\u9650\u7ba1\u7406\u5728\u7cfb\u7edf\u4e2d\u4e00\u822c\u5206\u4e3a\uff1a<\/p>\n<ul>\n<li>\u8bbf\u95ee\u6743\u9650\n<pre><code class=\"language-properties line-numbers\">\u4e00\u822c\u8868\u793a\u4f60\u80fd\u505a\u4ec0\u4e48\u6837\u7684\u64cd\u4f5c\uff0c\u6216\u8005\u80fd\u591f\u8bbf\u95ee\u90a3\u4e9b\u8d44\u6e90\u3002\u4f8b\u5982\uff1a\u7ed9\u5f20\u4e09\u8d4b\u4e88\u201c\u5e97\u94fa\u4e3b\u7ba1\u201d\u89d2\u8272\uff0c\u201c\u5e97\u94fa\u4e3b\u7ba1\u201d\u5177\u6709\u201c\u67e5\u8be2\u5458\u5de5\u201d\u3001\u201c\u6dfb\u52a0\u5458\u5de5\u201d\u3001\u201c\u4fee\u6539\u5458\u5de5\u201d\u548c\u201c\u5220\u9664\u5458\u5de5\u201d\u6743\u9650\u3002\u6b64\u65f6\u5f20\u4e09\u80fd\u591f\u8fdb\u5165\u7cfb\u7edf\uff0c\u5219\u53ef\u4ee5\u8fdb\u884c\u8fd9\u4e9b\u64cd\u4f5c\n<\/code><\/pre>\n<\/li>\n<li>\u6570\u636e\u6743\u9650\n<pre><code class=\"language-properties line-numbers\">\u4e00\u822c\u8868\u793a\u67d0\u4e9b\u6570\u636e\u4f60\u662f\u5426\u5c5e\u4e8e\u4f60\uff0c\u6216\u8005\u5c5e\u4e8e\u4f60\u53ef\u4ee5\u64cd\u4f5c\u8303\u56f4\u3002\u4f8b\u5982\uff1a\u5f20\u4e09\u662f\"\u5e97\u94fa\u4e3b\u7ba1\"\u89d2\u8272\uff0c\u4ed6\u53ef\u4ee5\u770b\u4ed6\u624b\u4e0b\u5ba2\u670d\u4eba\u5458\u6240\u6709\u7684\u670d\u52a1\u7684\u4e70\u5bb6\u8ba2\u5355\u4fe1\u606f\uff0c\u4ed6\u7684\u624b\u4e0b\u53ea\u80fd\u770b\u81ea\u5df1\u8d1f\u8d23\u7684\u8ba2\u5355\u4fe1\u606f\n<\/code><\/pre>\n<\/li>\n<\/ul>\n<h3>2\u3001\u8ba4\u8bc1\u6982\u5ff5<\/h3>\n<h4>\u30101\u3011\u4ec0\u4e48\u662f\u8ba4\u8bc1<\/h4>\n<p>\u200b       \u8eab\u4efd\u8ba4\u8bc1\uff0c\u5c31\u662f\u5224\u65ad\u4e00\u4e2a\u7528\u6237\u662f\u5426\u4e3a\u5408\u6cd5\u7528\u6237\u7684\u5904\u7406\u8fc7\u7a0b\u3002\u6700\u5e38\u7528\u7684\u7b80\u5355\u8eab\u4efd\u8ba4\u8bc1\u65b9\u5f0f\u662f\u7cfb\u7edf\u901a\u8fc7\u6838\u5bf9\u7528\u6237\u8f93\u5165\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u770b\u5176\u662f\u5426\u4e0e\u7cfb\u7edf\u4e2d\u5b58\u50a8\u7684\u8be5\u7528\u6237\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\u4e00\u81f4\uff0c\u6765\u5224\u65ad\u7528\u6237\u8eab\u4efd\u662f\u5426\u6b63\u786e\u3002\u4f8b\u5982\uff1a\u5bc6\u7801\u767b\u5f55\uff0c\u624b\u673a\u77ed\u4fe1\u9a8c\u8bc1\u3001\u4e09\u65b9\u6388\u6743\u7b49<\/p>\n<h4>\u30102\u3011\u8ba4\u8bc1\u6d41\u7a0b<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580044671870.png\" alt=\"1580044671870\" \/><\/p>\n<h4>\u30103\u3011\u5173\u952e\u5bf9\u8c61<\/h4>\n<p>\u200b       \u4e0a\u8fb9\u7684\u6d41\u7a0b\u56fe\u4e2d\u9700\u8981\u7406\u89e3\u4ee5\u4e0b\u5173\u952e\u5bf9\u8c61\uff1a<\/p>\n<p>\u200b        <strong>Subject<\/strong>\uff1a\u4e3b\u4f53\uff1a\u8bbf\u95ee\u7cfb\u7edf\u7684\u7528\u6237\uff0c\u4e3b\u4f53\u53ef\u4ee5\u662f\u7528\u6237\u3001\u7a0b\u5e8f\u7b49\uff0c\u8fdb\u884c\u8ba4\u8bc1\u7684\u90fd\u79f0\u4e3a\u4e3b\u4f53\uff1b<\/p>\n<p>\u200b        <strong>Principal<\/strong>\uff1a\u8eab\u4efd\u4fe1\u606f\u662f\u4e3b\u4f53\uff08subject\uff09\u8fdb\u884c\u8eab\u4efd\u8ba4\u8bc1\u7684\u6807\u8bc6\uff0c\u6807\u8bc6\u5fc5\u987b\u5177\u6709\u552f\u4e00\u6027\uff0c\u5982\u7528\u6237\u540d\u3001\u624b\u673a\u53f7\u3001\u90ae\u7bb1\u5730\u5740\u7b49\uff0c\u4e00\u4e2a\u4e3b\u4f53\u53ef\u4ee5\u6709\u591a\u4e2a\u8eab\u4efd\uff0c\u4f46\u662f\u5fc5\u987b\u6709\u4e00\u4e2a\u4e3b\u8eab\u4efd\uff08Primary Principal\uff09\u3002<\/p>\n<p>\u200b        <strong>credential<\/strong>\uff1a\u51ed\u8bc1\u4fe1\u606f\uff1a\u662f\u53ea\u6709\u4e3b\u4f53\u81ea\u5df1\u77e5\u9053\u7684\u5b89\u5168\u4fe1\u606f\uff0c\u5982\u5bc6\u7801\u3001\u8bc1\u4e66\u7b49\u3002<\/p>\n<h3>3\u3001\u6388\u6743\u6982\u5ff5<\/h3>\n<h4>\u30101\u3011\u4ec0\u4e48\u662f\u6388\u6743<\/h4>\n<p>\u200b       \u6388\u6743\uff0c\u5373\u8bbf\u95ee\u63a7\u5236\uff0c\u63a7\u5236\u8c01\u80fd\u8bbf\u95ee\u54ea\u4e9b\u8d44\u6e90\u3002\u4e3b\u4f53\u8fdb\u884c\u8eab\u4efd\u8ba4\u8bc1\u540e\uff0c\u7cfb\u7edf\u4f1a\u4e3a\u5176\u5206\u914d\u5bf9\u5e94\u7684\u6743\u9650\uff0c\u5f53\u8bbf\u95ee\u8d44<\/p>\n<p>\u6e90\u65f6\uff0c\u4f1a\u6821\u9a8c\u5176\u662f\u5426\u6709\u8bbf\u95ee\u6b64\u8d44\u6e90\u7684\u6743\u9650\u3002<\/p>\n<p>\u8fd9\u91cc\u9996\u5148\u7406\u89e34\u4e2a\u5bf9\u8c61\u3002<\/p>\n<p>\u200b       \u7528\u6237\u5bf9\u8c61user\uff1a\u5f53\u524d\u64cd\u4f5c\u7684\u7528\u6237\u3001\u7a0b\u5e8f\u3002<\/p>\n<p>\u200b       \u8d44\u6e90\u5bf9\u8c61resource\uff1a\u5f53\u524d\u88ab\u8bbf\u95ee\u7684\u5bf9\u8c61<\/p>\n<p>\u200b       \u89d2\u8272\u5bf9\u8c61role \uff1a\u4e00\u7ec4 &#8220;\u6743\u9650\u64cd\u4f5c\u8bb8\u53ef\u6743&#8221; \u7684\u96c6\u5408\u3002<\/p>\n<p>\u200b       \u6743\u9650\u5bf9\u8c61permission\uff1a\u6743\u9650\u64cd\u4f5c\u8bb8\u53ef\u6743<\/p>\n<h4>\u30102\u3011\u6388\u6743\u6d41\u7a0b<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582789303655.png\" alt=\"1582789303655\" \/><\/p>\n<h4>\u30103\u3011\u5173\u952e\u5bf9\u8c61<\/h4>\n<p><strong>\u6388\u6743\u53ef\u7b80\u5355\u7406\u89e3\u4e3awho\u5bf9what\u8fdb\u884cHow\u64cd\u4f5c<\/strong><\/p>\n<p><strong>Who\uff1a<\/strong>\u4e3b\u4f53\uff08Subject\uff09\uff0c\u53ef\u4ee5\u662f\u4e00\u4e2a\u7528\u6237\u3001\u4e5f\u53ef\u4ee5\u662f\u4e00\u4e2a\u7a0b\u5e8f<\/p>\n<p><strong>What\uff1a<\/strong>\u8d44\u6e90\uff08Resource\uff09\uff0c\u5982\u7cfb\u7edf\u83dc\u5355\u3001\u9875\u9762\u3001\u6309\u94ae\u3001\u65b9\u6cd5\u3001\u7cfb\u7edf\u5546\u54c1\u4fe1\u606f\u7b49\u3002<\/p>\n<p>\u200b       \u8bbf\u95ee\u7c7b\u578b\uff1a\u5546\u54c1\u83dc\u5355\uff0c\u8ba2\u5355\u83dc\u5355\u3001\u5206\u9500\u5546\u83dc\u5355<\/p>\n<p>\u200b       \u6570\u636e\u7c7b\u578b\uff1a\u6211\u7684\u5546\u54c1\uff0c\u6211\u7684\u8ba2\u5355\uff0c\u6211\u7684\u8bc4\u4ef7<\/p>\n<p><strong>How\uff1a<\/strong>\u6743\u9650\/\u8bb8\u53ef\uff08Permission\uff09<\/p>\n<p>\u200b       \u6211\u7684\u5546\u54c1\uff08\u8d44\u6e90\uff09<span class=\"text-highlighted-inline\" style=\"background-color: #fffd38;\">=>\u8bbf\u95ee\u6211\u7684\u5546\u54c1(\u6743\u9650\u8bb8\u53ef)<\/span><\/p>\n<p>\u200b       \u5206\u9500\u5546\u83dc\u5355\uff08\u8d44\u6e90\uff09<span class=\"text-highlighted-inline\" style=\"background-color: #fffd38;\">=\u300b\u8bbf\u95ee\u5206\u9500\u5546\u5217\u8868\uff08\u6743\u9650\u8bb8\u53ef\uff09      <\/span><\/p>\n<h2>\u7b2c\u4e8c\u7ae0 Shiro\u6982\u8ff0<\/h2>\n<h3>1\u3001Shiro\u7b80\u4ecb<\/h3>\n<h4>\u30101\u3011\u4ec0\u4e48\u662fShiro?<\/h4>\n<p>\u200b       Shiro\u662fapache\u65d7\u4e0b\u4e00\u4e2a\u5f00\u6e90\u6846\u67b6\uff0c\u5b83\u5c06\u8f6f\u4ef6\u7cfb\u7edf\u7684\u5b89\u5168\u8ba4\u8bc1\u76f8\u5173\u7684\u529f\u80fd\u62bd\u53d6\u51fa\u6765\uff0c\u5b9e\u73b0\u7528\u6237\u8eab\u4efd\u8ba4\u8bc1\uff0c\u6743\u9650\u6388\u6743\u3001\u52a0\u5bc6\u3001\u4f1a\u8bdd\u7ba1\u7406\u7b49\u529f\u80fd\uff0c\u7ec4\u6210\u4e86\u4e00\u4e2a\u901a\u7528\u7684\u5b89\u5168\u8ba4\u8bc1\u6846\u67b6\u3002<\/p>\n<h4>\u30102\u3011Shiro \u7684\u7279\u70b9<\/h4>\n<p>\u200b       Shiro \u662f\u4e00\u4e2a\u5f3a\u5927\u800c\u7075\u6d3b\u7684\u5f00\u6e90\u5b89\u5168\u6846\u67b6\uff0c\u80fd\u591f\u975e\u5e38\u6e05\u6670\u7684\u5904\u7406\u8ba4\u8bc1\u3001\u6388\u6743\u3001\u7ba1\u7406\u4f1a\u8bdd\u4ee5\u53ca\u5bc6\u7801\u52a0\u5bc6\u3002\u5982\u4e0b\u662f\u5b83\u6240\u5177\u6709\u7684\u7279\u70b9\uff1a<\/p>\n<p>\u00b7 \u6613\u4e8e\u7406\u89e3\u7684 Java Security API\uff1b<\/p>\n<p>\u00b7 \u7b80\u5355\u7684\u8eab\u4efd\u8ba4\u8bc1\uff08\u767b\u5f55\uff09\uff0c\u652f\u6301\u591a\u79cd\u6570\u636e\u6e90\uff08LDAP\uff0cJDBC \u7b49\uff09\uff1b<\/p>\n<p>\u00b7 \u5bf9\u89d2\u8272\u7684\u7b80\u5355\u7684\u7b7e\u6743\uff08\u8bbf\u95ee\u63a7\u5236\uff09\uff0c\u4e5f\u652f\u6301\u7ec6\u7c92\u5ea6\u7684\u9274\u6743\uff1b<\/p>\n<p>\u00b7 \u652f\u6301\u4e00\u7ea7\u7f13\u5b58\uff0c\u4ee5\u63d0\u5347\u5e94\u7528\u7a0b\u5e8f\u7684\u6027\u80fd\uff1b<\/p>\n<p>\u00b7 \u5185\u7f6e\u7684\u57fa\u4e8e POJO \u4f01\u4e1a\u4f1a\u8bdd\u7ba1\u7406\uff0c\u9002\u7528\u4e8e Web \u4ee5\u53ca\u975e Web \u7684\u73af\u5883\uff1b<\/p>\n<p>\u00b7 \u5f02\u6784\u5ba2\u6237\u7aef\u4f1a\u8bdd\u8bbf\u95ee\uff1b<\/p>\n<p>\u00b7 \u975e\u5e38\u7b80\u5355\u7684\u52a0\u5bc6 API\uff1b<\/p>\n<p>\u00b7 \u4e0d\u8ddf\u4efb\u4f55\u7684\u6846\u67b6\u6216\u8005\u5bb9\u5668\u6346\u7ed1\uff0c\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u3002<\/p>\n<h3>2\u3001\u6838\u5fc3\u7ec4\u4ef6<\/h3>\n<ul>\n<li>Shiro\u67b6\u6784\u56fe<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/9b959a65-799d-396e-b5f5-b4fcfe88f53c.png\" alt=\"\" \/><\/p>\n<ul>\n<li>Subject<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">Subject\u4e3b\u4f53\uff0c\u5916\u90e8\u5e94\u7528\u4e0esubject\u8fdb\u884c\u4ea4\u4e92\uff0csubject\u5c06\u7528\u6237\u4f5c\u4e3a\u5f53\u524d\u64cd\u4f5c\u7684\u4e3b\u4f53\uff0c\u8fd9\u4e2a\u4e3b\u4f53\uff1a\u53ef\u4ee5\u662f\u4e00\u4e2a\u901a\u8fc7\u6d4f\u89c8\u5668\u8bf7\u6c42\u7684\u7528\u6237\uff0c\u4e5f\u53ef\u80fd\u662f\u4e00\u4e2a\u8fd0\u884c\u7684\u7a0b\u5e8f\u3002Subject\u5728shiro\u4e2d\u662f\u4e00\u4e2a\u63a5\u53e3\uff0c\u63a5\u53e3\u4e2d\u5b9a\u4e49\u4e86\u5f88\u591a\u8ba4\u8bc1\u6388\u76f8\u5173\u7684\u65b9\u6cd5\uff0c\u5916\u90e8\u7a0b\u5e8f\u901a\u8fc7subject\u8fdb\u884c\u8ba4\u8bc1\u6388\uff0c\u800csubject\u662f\u901a\u8fc7SecurityManager\u5b89\u5168\u7ba1\u7406\u5668\u8fdb\u884c\u8ba4\u8bc1\u6388\u6743\n<\/code><\/pre>\n<ul>\n<li>SecurityManager<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">SecurityManager\u6743\u9650\u7ba1\u7406\u5668\uff0c\u5b83\u662fshiro\u7684\u6838\u5fc3\uff0c\u8d1f\u8d23\u5bf9\u6240\u6709\u7684subject\u8fdb\u884c\u5b89\u5168\u7ba1\u7406\u3002\u901a\u8fc7SecurityManager\u53ef\u4ee5\u5b8c\u6210subject\u7684\u8ba4\u8bc1\u3001\u6388\u6743\u7b49\uff0cSecurityManager\u662f\u901a\u8fc7Authenticator\u8fdb\u884c\u8ba4\u8bc1\uff0c\u901a\u8fc7Authorizer\u8fdb\u884c\u6388\u6743\uff0c\u901a\u8fc7SessionManager\u8fdb\u884c\u4f1a\u8bdd\u7ba1\u7406\u7b49\u3002SecurityManager\u662f\u4e00\u4e2a\u63a5\u53e3\uff0c\u7ee7\u627f\u4e86Authenticator, Authorizer, SessionManager\u8fd9\u4e09\u4e2a\u63a5\u53e3\n<\/code><\/pre>\n<ul>\n<li>Authenticator<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">Authenticator\u5373\u8ba4\u8bc1\u5668\uff0c\u5bf9\u7528\u6237\u767b\u5f55\u65f6\u8fdb\u884c\u8eab\u4efd\u8ba4\u8bc1\n<\/code><\/pre>\n<ul>\n<li>Authorizer<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">Authorizer\u6388\u6743\u5668\uff0c\u7528\u6237\u901a\u8fc7\u8ba4\u8bc1\u5668\u8ba4\u8bc1\u901a\u8fc7\uff0c\u5728\u8bbf\u95ee\u529f\u80fd\u65f6\u9700\u8981\u901a\u8fc7\u6388\u6743\u5668\u5224\u65ad\u7528\u6237\u662f\u5426\u6709\u6b64\u529f\u80fd\u7684\u64cd\u4f5c\u6743\u9650\u3002\n<\/code><\/pre>\n<ul>\n<li>Realm\uff08\u6570\u636e\u5e93\u8bfb\u53d6+\u8ba4\u8bc1\u529f\u80fd+\u6388\u6743\u529f\u80fd\u5b9e\u73b0\uff09<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">Realm\u9886\u57df\uff0c\u76f8\u5f53\u4e8edatasource\u6570\u636e\u6e90\uff0csecurityManager\u8fdb\u884c\u5b89\u5168\u8ba4\u8bc1\u9700\u8981\u901a\u8fc7Realm\u83b7\u53d6\u7528\u6237\u6743\u9650\u6570\u636e\n\u6bd4\u5982\uff1a\n    \u5982\u679c\u7528\u6237\u8eab\u4efd\u6570\u636e\u5728\u6570\u636e\u5e93\u90a3\u4e48realm\u5c31\u9700\u8981\u4ece\u6570\u636e\u5e93\u83b7\u53d6\u7528\u6237\u8eab\u4efd\u4fe1\u606f\u3002\n\u6ce8\u610f\uff1a\n    \u4e0d\u8981\u628arealm\u7406\u89e3\u6210\u53ea\u662f\u4ece\u6570\u636e\u6e90\u53d6\u6570\u636e\uff0c\u5728realm\u4e2d\u8fd8\u6709\u8ba4\u8bc1\u6388\u6743\u6821\u9a8c\u7684\u76f8\u5173\u7684\u4ee3\u7801\u3002\u3000\n<\/code><\/pre>\n<ul>\n<li>SessionManager<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">SessionManager\u4f1a\u8bdd\u7ba1\u7406\uff0cshiro\u6846\u67b6\u5b9a\u4e49\u4e86\u4e00\u5957\u4f1a\u8bdd\u7ba1\u7406\uff0c\u5b83\u4e0d\u4f9d\u8d56web\u5bb9\u5668\u7684session\uff0c\u6240\u4ee5shiro\u53ef\u4ee5\u4f7f\u7528\u5728\u975eweb\u5e94\u7528\u4e0a\uff0c\u4e5f\u53ef\u4ee5\u5c06\u5206\u5e03\u5f0f\u5e94\u7528\u7684\u4f1a\u8bdd\u96c6\u4e2d\u5728\u4e00\u70b9\u7ba1\u7406\uff0c\u6b64\u7279\u6027\u53ef\u4f7f\u5b83\u5b9e\u73b0\u5355\u70b9\u767b\u5f55\u3002\n\n<\/code><\/pre>\n<ul>\n<li>SessionDAO<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">SessionDAO\u5373\u4f1a\u8bdddao\uff0c\u662f\u5bf9session\u4f1a\u8bdd\u64cd\u4f5c\u7684\u4e00\u5957\u63a5\u53e3\n\u6bd4\u5982:\n    \u53ef\u4ee5\u901a\u8fc7jdbc\u5c06\u4f1a\u8bdd\u5b58\u50a8\u5230\u6570\u636e\u5e93\n    \u4e5f\u53ef\u4ee5\u628asession\u5b58\u50a8\u5230\u7f13\u5b58\u670d\u52a1\u5668\n\n<\/code><\/pre>\n<ul>\n<li>CacheManager<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">CacheManager\u7f13\u5b58\u7ba1\u7406\uff0c\u5c06\u7528\u6237\u6743\u9650\u6570\u636e\u5b58\u50a8\u5728\u7f13\u5b58\uff0c\u8fd9\u6837\u53ef\u4ee5\u63d0\u9ad8\u6027\u80fd\n\n<\/code><\/pre>\n<ul>\n<li>Cryptography<\/li>\n<\/ul>\n<pre><code class=\"line-numbers\">Cryptography\u5bc6\u7801\u7ba1\u7406\uff0cshiro\u63d0\u4f9b\u4e86\u4e00\u5957\u52a0\u5bc6\/\u89e3\u5bc6\u7684\u7ec4\u4ef6\uff0c\u65b9\u4fbf\u5f00\u53d1\u3002\u6bd4\u5982\u63d0\u4f9b\u5e38\u7528\u7684\u6563\u5217\u3001\u52a0\/\u89e3\u5bc6\u7b49\u529f\u80fd\n\n<\/code><\/pre>\n<h2>\u7b2c\u4e09\u7ae0 Shiro\u5165\u95e8<\/h2>\n<h3>1\u3001\u8eab\u4efd\u8ba4\u8bc1<\/h3>\n<h4>\u30101\u3011\u57fa\u672c\u6d41\u7a0b<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580047247677.png\" alt=\"1580047247677\" \/><\/p>\n<p>\u6d41\u7a0b\u5982\u4e0b\uff1a<\/p>\n<p>\u200b   1\u3001Shiro\u628a\u7528\u6237\u7684\u6570\u636e\u5c01\u88c5\u6210\u6807\u8bc6token\uff0ctoken\u4e00\u822c\u5c01\u88c5\u7740\u7528\u6237\u540d\uff0c\u5bc6\u7801\u7b49\u4fe1\u606f<\/p>\n<p>\u200b   2\u3001\u4f7f\u7528Subject\u95e8\u9762\u83b7\u53d6\u5230\u5c01\u88c5\u7740\u7528\u6237\u7684\u6570\u636e\u7684\u6807\u8bc6token<\/p>\n<p>\u200b   3\u3001Subject\u628a\u6807\u8bc6token\u4ea4\u7ed9SecurityManager\uff0c\u5728SecurityManager\u5b89\u5168\u4e2d\u5fc3\u4e2d\uff0cSecurityManager\u628a\u6807\u8bc6token\u59d4\u6258\u7ed9\u8ba4\u8bc1\u5668Authenticator\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002\u8ba4\u8bc1\u5668\u7684\u4f5c\u7528\u4e00\u822c\u662f\u7528\u6765\u6307\u5b9a\u5982\u4f55\u9a8c\u8bc1\uff0c\u5b83\u89c4\u5b9a\u672c\u6b21\u8ba4\u8bc1\u7528\u5230\u54ea\u4e9bRealm<\/p>\n<p>\u200b   4\u3001\u8ba4\u8bc1\u5668Authenticator\u5c06\u4f20\u5165\u7684\u6807\u8bc6token\uff0c\u4e0e\u6570\u636e\u6e90Realm\u5bf9\u6bd4\uff0c\u9a8c\u8bc1token\u662f\u5426\u5408\u6cd5<\/p>\n<h4>\u30102\u3011\u6848\u4f8b\u6f14\u793a<\/h4>\n<h5>\u30102.1\u3011\u9700\u6c42<\/h5>\n<pre><code class=\"line-numbers\">1\u3001\u4f7f\u7528shiro\u5b8c\u6210\u4e00\u4e2a\u7528\u6237\u7684\u767b\u5f55\n\n<\/code><\/pre>\n<h5>\u30102.2\u3011\u5b9e\u73b0<\/h5>\n<h6>\u30102.2.1\u3011\u65b0\u5efa\u9879\u76ee<\/h6>\n<p>shiro-day01-01authenticator<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580048751209.png\" alt=\"1580048751209\" \/><\/p>\n<h6>\u30102.2.2\u3011\u5bfc\u5165\u4f9d\u8d56<\/h6>\n<pre data-language=XML><code class=\"language-markup line-numbers\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n  xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n\n  &lt;groupId&gt;com.itheima.shiro&lt;\/groupId&gt;\n  &lt;artifactId&gt;shiro-day01-01authenticator&lt;\/artifactId&gt;\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\n\n  &lt;name&gt;shiro-day01-01authenticator&lt;\/name&gt;\n  &lt;!-- FIXME change it to the project's website --&gt;\n  &lt;url&gt;http:\/\/www.example.com&lt;\/url&gt;\n\n  &lt;properties&gt;\n    &lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\n  &lt;\/properties&gt;\n\n  &lt;dependencies&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;commons-logging&lt;\/groupId&gt;\n      &lt;artifactId&gt;commons-logging&lt;\/artifactId&gt;\n      &lt;version&gt;1.1.3&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.apache.shiro&lt;\/groupId&gt;\n      &lt;artifactId&gt;shiro-core&lt;\/artifactId&gt;\n      &lt;version&gt;1.3.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;junit&lt;\/groupId&gt;\n      &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n      &lt;version&gt;4.11&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n  &lt;\/dependencies&gt;\n\n  &lt;build&gt;\n    &lt;plugins&gt;\n      &lt;!-- compiler\u63d2\u4ef6, \u8bbe\u5b9aJDK\u7248\u672c --&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n        &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;3.1&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;source&gt;8&lt;\/source&gt;\n          &lt;target&gt;8&lt;\/target&gt;\n          &lt;showWarnings&gt;true&lt;\/showWarnings&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n    &lt;\/plugins&gt;\n  &lt;\/build&gt;\n&lt;\/project&gt;\n\n\n<\/code><\/pre>\n<h6>\u30102.2.3\u3011\u7f16\u5199shiro.ini<\/h6>\n<pre><code class=\"language-ini line-numbers\">#\u58f0\u660e\u7528\u6237\u8d26\u53f7\n[users]\njay=123\n\n<\/code><\/pre>\n<h6>\u30102.2.4\u3011\u7f16\u5199HelloShiro<\/h6>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.config.IniSecurityManagerFactory;\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.util.Factory;\nimport org.junit.Test;\n\n\/**\n * @Description\uff1ashiro\u7684\u7b2c\u4e00\u4e2a\u4f8b\u5b50\n *\/\npublic class HelloShiro {\n\n    @Test\n    public void shiroLogin() {\n        \/\/\u5bfc\u5165\u6743\u9650ini\u6587\u4ef6\u6784\u5efa\u6743\u9650\u5de5\u5382\n        Factory&lt;SecurityManager&gt; factory = new IniSecurityManagerFactory(\"classpath:shiro.ini\");\n        \/\/\u5de5\u5382\u6784\u5efa\u5b89\u5168\u7ba1\u7406\u5668\n        SecurityManager securityManager = factory.getInstance();\n        \/\/\u4f7f\u7528SecurityUtils\u5de5\u5177\u751f\u6548\u5b89\u5168\u7ba1\u7406\u5668\n        SecurityUtils.setSecurityManager(securityManager);\n        \/\/\u4f7f\u7528SecurityUtils\u5de5\u5177\u83b7\u5f97\u4e3b\u4f53\n        Subject subject = SecurityUtils.getSubject();\n        \/\/\u6784\u5efa\u8d26\u53f7token\n        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(\"jay\", \"123\");\n        \/\/\u767b\u5f55\u64cd\u4f5c\n        subject.login(usernamePasswordToken);\n        System.out.println(\"\u662f\u5426\u767b\u5f55\u6210\u529f\uff1a\" + subject.isAuthenticated());\n    }\n}\n\n\n<\/code><\/pre>\n<p>\u30102.2.4\u3011\u6d4b\u8bd5<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580049504816.png\" alt=\"1580049504816\" \/><\/p>\n<h5>\u30102.3\u3011\u5c0f\u7ed3<\/h5>\n<pre><code class=\"line-numbers\">1\u3001\u6743\u9650\u5b9a\u4e49\uff1aini\u6587\u4ef6\n2\u3001\u52a0\u8f7d\u8fc7\u7a0b:\n    \u5bfc\u5165\u6743\u9650ini\u6587\u4ef6\u6784\u5efa\u6743\u9650\u5de5\u5382\n    \u5de5\u5382\u6784\u5efa\u5b89\u5168\u7ba1\u7406\u5668\n    \u4f7f\u7528SecurityUtils\u5de5\u5177\u751f\u6548\u5b89\u5168\u7ba1\u7406\u5668\n    \u4f7f\u7528SecurityUtils\u5de5\u5177\u83b7\u5f97\u4e3b\u4f53\n    \u4f7f\u6784\u5efa\u8d26\u53f7token\u7528SecurityUtils\u5de5\u5177\u83b7\u5f97\u4e3b\u4f53\n    \u6784\u5efa\u8d26\u53f7token\n    \u767b\u5f55\u64cd\u4f5c\n\n<\/code><\/pre>\n<h3>2\u3001Realm<\/h3>\n<h4>\u30101\u3011Realm\u63a5\u53e3<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580050317405.png\" alt=\"1580050317405\" \/><\/p>\n<p>\u6240\u4ee5\uff0c\u4e00\u822c\u5728\u771f\u5b9e\u7684\u9879\u76ee\u4e2d\uff0c\u6211\u4eec\u4e0d\u4f1a\u76f4\u63a5\u5b9e\u73b0Realm\u63a5\u53e3\uff0c\u6211\u4eec\u4e00\u822c\u7684\u60c5\u51b5\u5c31\u662f\u76f4\u63a5\u7ee7\u627fAuthorizingRealm\uff0c\u80fd\u591f\u7ee7\u627f\u5230\u8ba4\u8bc1\u4e0e\u6388\u6743\u529f\u80fd\u3002\u5b83\u9700\u8981\u5f3a\u5236\u91cd\u5199\u4e24\u4e2a\u65b9\u6cd5<\/p>\n<pre><code class=\"language-java line-numbers\">public class DefinitionRealm extends AuthorizingRealm {\n\n    \/**\n     * @Description \u8ba4\u8bc1\n     * @param authcToken token\u5bf9\u8c61\n     * @return \n     *\/\n    public abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {\n        return null;\n    }\n\n    \/**\n     * @Description \u9274\u6743\n     * @param principals \u4ee4\u724c\n     * @return\n     *\/\n    public abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){\n        return null;\n    }\n}\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u81ea\u5b9a\u4e49Realm<\/h4>\n<h5>\u30102.1\u3011\u9700\u6c42<\/h5>\n<pre><code class=\"line-numbers\">1\u3001\u81ea\u5b9a\u4e49Realm\uff0c\u53d6\u5f97\u5bc6\u7801\u7528\u4e8e\u6bd4\u8f83\n<\/code><\/pre>\n<h5>\u30102.2\u3011\u5b9e\u73b0<\/h5>\n<h6>\u30102.2.1\u3011\u521b\u5efa\u9879\u76ee<\/h6>\n<p>shiro-day01-02realm<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580107180701.png\" alt=\"1580107180701\" \/><\/p>\n<h6>\u30102.2.2\u3011\u5b9a\u4e49SecurityService<\/h6>\n<p>SecurityService<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service;\n\n\/**\n * @Description\uff1a\u6743\u9650\u670d\u52a1\u63a5\u53e3\n *\/\npublic interface SecurityService {\n\n    \/**\n     * @Description \u67e5\u627e\u5bc6\u7801\u6309\u7528\u6237\u767b\u5f55\u540d\n     * @param loginName \u767b\u5f55\u540d\u79f0\n     * @return\n     *\/\n    String findPasswordByLoginName(String loginName);\n}\n\n<\/code><\/pre>\n<p>SecurityServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.itheima.shiro.service.SecurityService;\n\n\/**\n * @Description\uff1a\u6743\u9650\u670d\u52a1\u5c42\n *\/\npublic class SecurityServiceImpl implements SecurityService {\n\n    @Override\n    public String findPasswordByLoginName(String loginName) {\n        return \"123\";\n    }\n}\n\n<\/code><\/pre>\n<h6>\u30102.2.3\u3011\u5b9a\u4e49DefinitionRealm<\/h6>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.realm;\n\nimport com.itheima.shiro.service.SecurityService;\nimport com.itheima.shiro.service.impl.SecurityServiceImpl;\nimport org.apache.shiro.authc.*;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.realm.AuthorizingRealm;\nimport org.apache.shiro.subject.PrincipalCollection;\n\n\/**\n * @Description\uff1a\u58f0\u660e\u81ea\u5b9a\u4e49realm\n *\/\npublic class DefinitionRealm extends AuthorizingRealm {\n\n    \/**\n     * @Description \u8ba4\u8bc1\u63a5\u53e3\n     * @param token \u4f20\u9012\u767b\u5f55token\n     * @return\n     *\/\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {\n        \/\/\u4eceAuthenticationToken\u4e2d\u83b7\u5f97\u767b\u5f55\u540d\u79f0\n        String loginName = (String) token.getPrincipal();\n        SecurityService securityService = new SecurityServiceImpl();\n        String password = securityService.findPasswordByLoginName(loginName);\n        if (\"\".equals(password)||password==null){\n            throw new UnknownAccountException(\"\u8d26\u6237\u4e0d\u5b58\u5728\");\n        }\n        \/\/\u4f20\u9012\u8d26\u53f7\u548c\u5bc6\u7801\n        return  new SimpleAuthenticationInfo(loginName,password,getName());\n    }\n\n\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        return null;\n    }\n\n}\n\n\n<\/code><\/pre>\n<h6>\u30102.2.4\u3011\u7f16\u8f91shiro.ini<\/h6>\n<pre><code class=\"language-ini line-numbers\">#\u58f0\u660e\u81ea\u5b9a\u4e49\u7684realm\uff0c\u4e14\u4e3a\u5b89\u5168\u7ba1\u7406\u5668\u6307\u5b9arealms\n[main]\ndefinitionRealm=com.itheima.shiro.realm.DefinitionRealm\nsecurityManager.realms=$definitionRealm\n#\u58f0\u660e\u7528\u6237\u8d26\u53f7\n#[users]\n#jay=123\n\n<\/code><\/pre>\n<h4>\u30103\u3011\u8ba4\u8bc1\u6e90\u7801\u8ddf\u8e2a<\/h4>\n<p>\uff081\uff09\u901a\u8fc7debug\u6a21\u5f0f\u8ffd\u8e2a\u6e90\u7801subject.login(token) \u53d1\u73b0\u3002\u9996\u5148\u662f\u8fdb\u5165Subject\u63a5\u53e3\u7684\u9ed8\u8ba4\u5b9e\u73b0\u7c7b\u3002\u679c\u7136\uff0cSubject\u5c06\u7528\u6237\u7684\u7528\u6237\u540d\u5bc6\u7801\u59d4\u6258\u7ed9\u4e86securityManager\u53bb\u505a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580107715689.png\" alt=\"1580107715689\" \/><\/p>\n<p>\uff082\uff09\u7136\u540e\uff0csecurityManager\u8bf4\uff1a\u201c\u5367\u69fd\uff0c\u8ba4\u8bc1\u5668authenticator\u5c0f\u5f1f\uff0c\u542c\u8bf4\u4f60\u7684\u5927\u5b66\u5b66\u7684\u4e13\u4e1a\u5c31\u662f\u8ba4\u8bc1\u5440\uff0c\u90a3\u4e48\u8fd9\u4e2a\u8ba4\u8bc1\u7684\u4efb\u52a1\u5c31\u4ea4\u7ed9\u4f60\u54af\u201d\u3002\u9042\u5c06\u7528\u6237\u7684token\u59d4\u6258\u7ed9\u5185\u90e8\u8ba4\u8bc1\u7ec4\u4ef6authenticator\u53bb\u505a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580107767167.png\" alt=\"1580107767167\" \/><\/p>\n<p>\uff083\uff09\u4e8b\u5b9e\u4e0a\uff0csecurityManager\u7684\u5185\u90e8\u7ec4\u4ef6\u4e00\u4e2a\u6bd4\u4e00\u4e2a\u61d2\u3002\u5185\u90e8\u8ba4\u8bc1\u7ec4\u4ef6authenticator\u8bf4\uff1a\u201c\u4f60\u4eec\u4f20\u8fc7\u6765\u7684token\u6211\u9700\u8981\u62ff\u53bb\u8ddf\u6570\u636e\u6e90Realm\u505a\u5bf9\u6bd4\uff0c\u8fd9\u6837\u5427\uff0c\u8fd9\u4e2a\u5149\u8363\u7684\u4efb\u52a1\u5c31\u4ea4\u7ed9Realm\u4f60\u53bb\u505a\u5427\u201d\u3002Realm\u5bf9\u8c61\uff1a\u201c\u4e00\u7fa4\u5927\u61d2\u866b\uff01\u201d\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580107849133.png\" alt=\"1580107849133\" \/><\/p>\n<p>\uff084\uff09Realm\u5728\u63a5\u5230\u5185\u90e8\u8ba4\u8bc1\u7ec4\u4ef6authenticator\u7ec4\u4ef6\u540e\u5f88\u4f24\u5fc3\uff0c\u6700\u540e\u5bf9\u7535\u8111\u524d\u7684\u4f60\u8bf4\uff1a\u201c\u5927\u5144\u5f1f\uff0c\u5bf9\u4e0d\u4f4f\u4e86\uff0c\u4f60\u53bb\u5b9e\u73b0\u4e00\u4e0b\u5457\u201d\u3002\u4ece\u56fe\u4e2d\u7684\u65b9\u6cd5\u4f53\u4e2d\u53ef\u4ee5\u770b\u5230\uff0c\u5f53\u524d\u5bf9\u8c61\u662fRealm\u7c7b\u5bf9\u8c61\uff0c\u5373\u5c06\u8c03\u7528\u7684\u65b9\u6cd5\u662fdoGetAuthenticationInfo(token)\u3002\u800c\u8fd9\u4e2a\u65b9\u6cd5\uff0c\u5c31\u662f\u4f60\u5373\u5c06\u8981\u91cd\u5199\u7684\u65b9\u6cd5\u3002\u5982\u679c\u5e10\u53f7\u5bc6\u7801\u901a\u8fc7\u4e86\uff0c\u90a3\u4e48\u8fd4\u56de\u4e00\u4e2a\u8ba4\u8bc1\u6210\u529f\u7684info\u51ed\u8bc1\u3002\u5982\u679c\u8ba4\u8bc1\u5931\u8d25\uff0c\u629b\u51fa\u4e00\u4e2a\u5f02\u5e38\u5c31\u597d\u4e86\u3002\u4f60\u8bf4\uff1a\u201c\u4ec0\u4e48?\u6700\u7ec8\u8fd8\u662f\u52b3\u8d44\u6765\u8ba4\u8bc1\uff1f\u201d\u6ca1\u9519\uff0c\u5c31\u662f\u82e6\u903c\u7684\u4f60\u53bb\u5b9e\u73b0\u4e86\uff0c\u8c01\u53eb\u4f60\u662f\u7a0b\u5e8f\u733f\u5462\u3002\u6240\u4ee5\uff0c\u4f60\u4e0d\u5f97\u4e0d\u67e5\u8be2\u4e00\u4e0b\u6570\u636e\u5e93\uff0c\u91cd\u5199doGetAuthenticationInfo\u65b9\u6cd5\uff0c\u67e5\u51fa\u6765\u6b63\u786e\u7684\u5e10\u53f7\u5bc6\u7801\uff0c\u8fd4\u56de\u4e00\u4e2a\u6b63\u786e\u7684\u51ed\u8bc1info<br \/>\n<img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580108004686.png\" alt=\"1580108004686\" \/><\/p>\n<p>\uff085\uff09\u597d\u4e86\uff0c\u8fd9\u4e2a\u65f6\u5019\u4f60\u81ea\u5df1\u7f16\u5199\u4e86\u4e00\u4e2a\u7c7b\uff0c\u7ee7\u627f\u4e86AuthorizingRealm\uff0c\u5e76\u5b9e\u73b0\u4e86\u4e0a\u8ff0doGetAuthenticationInfo\u65b9\u6cd5\u3002\u4f60\u5728doGetAuthenticationInfo\u4e2d\u7f16\u5199\u4e86\u67e5\u8be2\u6570\u636e\u5e93\u7684\u4ee3\u7801\uff0c\u5e76\u5c06\u6570\u636e\u5e93\u4e2d\u5b58\u653e\u7684\u7528\u6237\u540d\u4e0e\u5bc6\u7801\u5c01\u88c5\u6210\u4e86\u4e00\u4e2aAuthenticationInfo\u5bf9\u8c61\u8fd4\u56de\u3002\u53ef\u4ee5\u770b\u5230\u4e0b\u56fe\u4e2d\uff0cinfo\u8fd9\u4e2a\u5bf9\u8c61\u662f\u6709\u503c\u7684\uff0c\u8bf4\u660e\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u8be2\u51fa\u6765\u4e86\u6b63\u786e\u7684\u5e10\u53f7\u5bc6\u7801<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580108049930.png\" alt=\"1580108049930\" \/><\/p>\n<p>\uff086\uff09\u90a3\u4e48\uff0c\u63a5\u4e0b\u6765\u5c31\u5f88\u7b80\u5355\u4e86\u3002\u628a\u7528\u6237\u8f93\u5165\u7684\u5e10\u53f7\u5bc6\u7801\u4e0e\u521a\u624d\u4f60\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u51fa\u6765\u7684\u5e10\u53f7\u5bc6\u7801\u5bf9\u6bd4\u4e00\u4e0b\u5373\u53ef\u3002token\u5c01\u88c5\u7740\u7528\u6237\u7684\u5e10\u53f7\u5bc6\u7801\uff0cAuthenticationInfo\u5c01\u88c5\u7740\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u8be2\u51fa\u6765\u7684\u5e10\u53f7\u5bc6\u7801\u3002\u518d\u5f80\u4e0b\u8ffd\u8e2a\u4e00\u4e0b\u4ee3\u7801\uff0c\u6700\u7ec8\u5230\u4e86\u4e0b\u56fe\u4e2d\u7684\u6838\u5fc3\u533a\u57df\u3002\u5982\u679c\u6ca1\u6709\u62a5\u5f02\u5e38\uff0c\u8bf4\u660e\u672c\u6b21\u767b\u5f55\u6210\u529f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580192296050.png\" alt=\"1580192296050\" \/><\/p>\n<h3>3\u3001\u7f16\u7801\u3001\u6563\u5217\u7b97\u6cd5<\/h3>\n<h4>\u30101\u3011\u7f16\u7801\u4e0e\u89e3\u7801<\/h4>\n<p>Shiro\u63d0\u4f9b\u4e86base64\u548c16\u8fdb\u5236\u5b57\u7b26\u4e32\u7f16\u7801\/\u89e3\u7801\u7684API\u652f\u6301\uff0c\u65b9\u4fbf\u4e00\u4e9b\u7f16\u7801\u89e3\u7801\u64cd\u4f5c\u3002<\/p>\n<p>Shiro\u5185\u90e8\u7684\u4e00\u4e9b\u6570\u636e\u7684\u3010\u5b58\u50a8\/\u8868\u793a\u3011\u90fd\u4f7f\u7528\u4e86base64\u548c16\u8fdb\u5236\u5b57\u7b26\u4e32<\/p>\n<h5>\u30101.1\u3011\u9700\u6c42<\/h5>\n<pre><code class=\"line-numbers\">\u7406\u89e3base64\u548c16\u8fdb\u5236\u5b57\u7b26\u4e32\u7f16\u7801\/\u89e3\u7801\n\n<\/code><\/pre>\n<h5>\u30101.2\u3011\u65b0\u5efa\u9879\u76ee<\/h5>\n<p>\u65b0\u5efashiro-day01-03encode-decode<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580196809749.png\" alt=\"1580196809749\" \/><\/p>\n<h5>\u30101.3\u3011\u65b0\u5efaEncodesUtil<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.tools;\n\nimport org.apache.shiro.codec.Base64;\nimport org.apache.shiro.codec.Hex;\n\n\/**\n * @Description\uff1a\u5c01\u88c5base64\u548c16\u8fdb\u5236\u7f16\u7801\u89e3\u7801\u5de5\u5177\u7c7b\n *\/\npublic class EncodesUtil {\n\n    \/**\n     * @Description HEX-byte[]--String\u8f6c\u6362\n     * @param input \u8f93\u5165\u6570\u7ec4\n     * @return String\n     *\/\n    public static String encodeHex(byte[] input){\n        return Hex.encodeToString(input);\n    }\n\n    \/**\n     * @Description HEX-String--byte[]\u8f6c\u6362\n     * @param input \u8f93\u5165\u5b57\u7b26\u4e32\n     * @return byte\u6570\u7ec4\n     *\/\n    public static byte[] decodeHex(String input){\n        return Hex.decode(input);\n    }\n\n    \/**\n     * @Description Base64-byte[]--String\u8f6c\u6362\n     * @param input \u8f93\u5165\u6570\u7ec4\n     * @return String\n     *\/\n    public static String encodeBase64(byte[] input){\n        return Base64.encodeToString(input);\n    }\n\n    \/**\n     * @Description Base64-String--byte[]\u8f6c\u6362\n     * @param input \u8f93\u5165\u5b57\u7b26\u4e32\n     * @return byte\u6570\u7ec4\n     *\/\n    public static byte[] decodeBase64(String input){\n        return Base64.decode(input);\n    }\n\n}\n\n<\/code><\/pre>\n<h5>\u30101.4\u3011\u65b0\u5efaClientTest<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.tools.EncodesUtil;\nimport org.junit.Test;\n\n\/**\n * @Description\uff1a\u6d4b\u8bd5\n *\/\npublic class ClientTest {\n\n    \/**\n     * @Description \u6d4b\u8bd516\u8fdb\u5236\u7f16\u7801\n     *\/\n    @Test\n    public void testHex(){\n        String val = \"holle\";\n        String flag = EncodesUtil.encodeHex(val.getBytes());\n        String valHandler = new String(EncodesUtil.decodeHex(flag));\n        System.out.println(\"\u6bd4\u8f83\u7ed3\u679c\uff1a\"+val.equals(valHandler));\n    }\n\n    \/**\n     * @Description \u6d4b\u8bd5base64\u7f16\u7801\n     *\/\n    @Test\n    public void testBase64(){\n        String val = \"holle\";\n        String flag = EncodesUtil.encodeBase64(val.getBytes());\n        String valHandler = new String(EncodesUtil.decodeBase64(flag));\n        System.out.println(\"\u6bd4\u8f83\u7ed3\u679c\uff1a\"+val.equals(valHandler));\n    }\n\n\n}\n\n<\/code><\/pre>\n<p>\u30101.5\u3011\u5c0f\u7ed3<\/p>\n<pre><code class=\"line-numbers\">1\u3001shiro\u76ee\u524d\u652f\u6301\u7684\u7f16\u7801\u4e0e\u89e3\u7801\uff1a\n    base64\n   \uff08HEX\uff0916\u8fdb\u5236\u5b57\u7b26\u4e32\n2\u3001\u90a3\u4e48shiro\u7684\u7f16\u7801\u4e0e\u89e3\u7801\u4ec0\u4e48\u65f6\u5019\u4f7f\u7528\u5462\uff1f\u53c8\u662f\u600e\u4e48\u4f7f\u7528\u7684\u5462\uff1f\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u6563\u5217\u7b97\u6cd5<\/h4>\n<p>\u6563\u5217\u7b97\u6cd5\u4e00\u822c\u7528\u4e8e\u751f\u6210\u6570\u636e\u7684\u6458\u8981\u4fe1\u606f\uff0c\u662f\u4e00\u79cd\u4e0d\u53ef\u9006\u7684\u7b97\u6cd5\uff0c\u4e00\u822c\u9002\u5408\u5b58\u50a8\u5bc6\u7801\u4e4b\u7c7b\u7684\u6570\u636e\uff0c\u5e38\u89c1\u7684\u6563\u5217\u7b97\u6cd5\u5982MD5\u3001SHA\u7b49\u3002\u4e00\u822c\u8fdb\u884c\u6563\u5217\u65f6\u6700\u597d\u63d0\u4f9b\u4e00\u4e2asalt\uff08\u76d0\uff09\uff0c\u6bd4\u5982\u52a0\u5bc6\u5bc6\u7801\u201cadmin\u201d\uff0c\u4ea7\u751f\u7684\u6563\u5217\u503c\u662f\u201c21232f297a57a5a743894a0e4a801fc3\u201d\uff0c\u53ef\u4ee5\u5230\u4e00\u4e9bmd5\u89e3\u5bc6\u7f51\u7ad9\u5f88\u5bb9\u6613\u7684\u901a\u8fc7\u6563\u5217\u503c\u5f97\u5230\u5bc6\u7801\u201cadmin\u201d\uff0c\u5373\u5982\u679c\u76f4\u63a5\u5bf9\u5bc6\u7801\u8fdb\u884c\u6563\u5217\u76f8\u5bf9\u6765\u8bf4\u7834\u89e3\u66f4\u5bb9\u6613\uff0c\u6b64\u65f6\u6211\u4eec\u53ef\u4ee5\u52a0\u4e00\u4e9b\u53ea\u6709\u7cfb\u7edf\u77e5\u9053\u7684\u5e72\u6270\u6570\u636e\uff0c\u5982salt\uff08\u5373\u76d0\uff09\uff1b\u8fd9\u6837\u6563\u5217\u7684\u5bf9\u8c61\u662f\u201c\u5bc6\u7801+salt\u201d\uff0c\u8fd9\u6837\u751f\u6210\u7684\u6563\u5217\u503c\u76f8\u5bf9\u6765\u8bf4\u66f4\u96be\u7834\u89e3\u3002<\/p>\n<p>shiro\u652f\u6301\u7684\u6563\u5217\u7b97\u6cd5\uff1a<\/p>\n<p>Md2Hash\u3001Md5Hash\u3001Sha1Hash\u3001Sha256Hash\u3001Sha384Hash\u3001Sha512Hash<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580277706466.png\" alt=\"1580277706466\" \/><\/p>\n<h5>\u30102.1\u3011\u65b0\u589eDigestsUtil<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.tools;\n\nimport com.sun.org.apache.bcel.internal.generic.NEW;\nimport org.apache.shiro.crypto.SecureRandomNumberGenerator;\nimport org.apache.shiro.crypto.hash.SimpleHash;\nimport sun.security.util.Password;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u6458\u8981\n *\/\npublic class DigestsUtil {\n\n    private static final String SHA1 = \"SHA-1\";\n\n    private static final Integer ITERATIONS =512;\n\n    \/**\n     * @Description sha1\u65b9\u6cd5\n     * @param input \u9700\u8981\u6563\u5217\u5b57\u7b26\u4e32\n     * @param salt \u76d0\u5b57\u7b26\u4e32\n     * @return\n     *\/\n    public static String sha1(String input, String salt) {\n       return new SimpleHash(SHA1, input, salt,ITERATIONS).toString();\n    }\n\n    \/**\n     * @Description \u968f\u673a\u83b7\u5f97salt\u5b57\u7b26\u4e32\n     * @return\n     *\/\n    public static String generateSalt(){\n        SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();\n        return randomNumberGenerator.nextBytes().toHex();\n    }\n\n\n    \/**\n     * @Description \u751f\u6210\u5bc6\u7801\u5b57\u7b26\u5bc6\u6587\u548csalt\u5bc6\u6587\n     * @param\n     * @return\n     *\/\n    public static Map&lt;String,String&gt; entryptPassword(String passwordPlain) {\n       Map&lt;String,String&gt; map = new HashMap&lt;&gt;();\n       String salt = generateSalt();\n       String password =sha1(passwordPlain,salt);\n       map.put(\"salt\", salt);\n       map.put(\"password\", password);\n       return map;\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30102.2\u3011\u65b0\u589eClientTest<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.tools.DigestsUtil;\nimport com.itheima.shiro.tools.EncodesUtil;\nimport org.junit.Test;\n\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u6d4b\u8bd5\n *\/\npublic class ClientTest {\n\n    \/**\n     * @Description \u6d4b\u8bd516\u8fdb\u5236\u7f16\u7801\n     *\/\n    @Test\n    public void testHex(){\n        String val = \"holle\";\n        String flag = EncodesUtil.encodeHex(val.getBytes());\n        String valHandler = new String(EncodesUtil.decodeHex(flag));\n        System.out.println(\"\u6bd4\u8f83\u7ed3\u679c\uff1a\"+val.equals(valHandler));\n    }\n\n    \/**\n     * @Description \u6d4b\u8bd5base64\u7f16\u7801\n     *\/\n    @Test\n    public void testBase64(){\n        String val = \"holle\";\n        String flag = EncodesUtil.encodeBase64(val.getBytes());\n        String valHandler = new String(EncodesUtil.decodeBase64(flag));\n        System.out.println(\"\u6bd4\u8f83\u7ed3\u679c\uff1a\"+val.equals(valHandler));\n    }\n\n    @Test\n    public void testDigestsUtil(){\n       Map&lt;String,String&gt; map =  DigestsUtil.entryptPassword(\"123\");\n        System.out.println(\"\u83b7\u5f97\u7ed3\u679c\uff1a\"+map.toString());\n    }\n\n}\n\n\n<\/code><\/pre>\n<h3>4\u3001Realm\u4f7f\u7528\u6563\u5217\u7b97\u6cd5<\/h3>\n<p>\u4e0a\u9762\u6211\u4eec\u4e86\u89e3\u7f16\u7801\uff0c\u4ee5\u53ca\u6563\u5217\u7b97\u6cd5\uff0c\u90a3\u4e48\u5728realm\u4e2d\u600e\u4e48\u4f7f\u7528\uff1f\u5728shiro-day01-02realm\u4e2d\u6211\u4eec\u4f7f\u7528\u7684\u5bc6\u7801\u662f\u660e\u6587\u7684\u6821\u9a8c\u65b9\u5f0f\uff0c\u4e5f\u5c31\u662fSecurityServiceImpl\u4e2dfindPasswordByLoginName\u8fd4\u56de\u7684\u662f\u660e\u6587123\u7684\u5bc6\u7801<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.itheima.shiro.service.SecurityService;\n\n\/**\n * @Description\uff1a\u6743\u9650\u670d\u52a1\u5c42\n *\/\npublic class SecurityServiceImpl implements SecurityService {\n\n    @Override\n    public String findPasswordByLoginName(String loginName) {\n        return \"123\";\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30101\u3011\u65b0\u5efa\u9879\u76ee<\/h4>\n<p>shiro-day01-05-ciphertext-realm<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580281644492.png\" alt=\"1580281644492\" \/><\/p>\n<h4>\u30102\u3011\u521b\u5efa\u5bc6\u6587\u5bc6\u7801<\/h4>\n<p>\u4f7f\u7528ClientTest\u7684testDigestsUtil\u521b\u5efa\u5bc6\u7801\u4e3a\u201c123\u201d\u7684password\u5bc6\u6587\u548csalt\u5bc6\u6587<\/p>\n<pre><code class=\"line-numbers\">password:56265d624e484ca62c6dfbc523e6d6fc7932d0d5\nsalt:845a66ac80174c0e486db9354cf84f9a\n\n<\/code><\/pre>\n<h4>\u30103\u3011\u4fee\u6539SecurityService<\/h4>\n<p>SecurityService\u4fee\u6539\u6210\u8fd4\u56desalt\u548cpassword\u7684map<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service;\n\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u6743\u9650\u670d\u52a1\u63a5\u53e3\n *\/\npublic interface SecurityService {\n\n    \/**\n     * @Description \u67e5\u627e\u5bc6\u7801\u6309\u7528\u6237\u767b\u5f55\u540d\n     * @param loginName \u767b\u5f55\u540d\u79f0\n     * @return\n     *\/\n    Map&lt;String,String&gt; findPasswordByLoginName(String loginName);\n}\n\n\n<\/code><\/pre>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.itheima.shiro.service.SecurityService;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u6743\u9650\u670d\u52a1\u5c42\n *\/\npublic class SecurityServiceImpl implements SecurityService {\n\n    @Override\n    public Map&lt;String,String&gt; findPasswordByLoginName(String loginName) {\n        \/\/\u6a21\u62df\u6570\u636e\u5e93\u4e2d\u5b58\u50a8\u7684\u5bc6\u6587\u4fe1\u606f\n       return  DigestsUtil.entryptPassword(\"123\");\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30104\u3011\u6307\u5b9a\u5bc6\u7801\u5339\u914d\u65b9\u5f0f<\/h4>\n<p>\u4e3aDefinitionRealm\u7c7b\u6dfb\u52a0\u6784\u9020\u65b9\u6cd5\u5982\u4e0b\uff1a<\/p>\n<pre><code class=\"language-java line-numbers\">    \/**\n     * @Description \u6784\u9020\u51fd\u6570\n     *\/\npublic DefinitionRealm() {\n    \/\/\u6307\u5b9a\u5bc6\u7801\u5339\u914d\u65b9\u5f0f\u4e3asha1\n    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);\n    \/\/\u6307\u5b9a\u5bc6\u7801\u8fed\u4ee3\u6b21\u6570\n    matcher.setHashIterations(DigestsUtil.ITERATIONS);\n    \/\/\u4f7f\u7528\u7236\u4eb2\u65b9\u6cd5\u4f7f\u5339\u914d\u65b9\u5f0f\u751f\u6548\n    setCredentialsMatcher(matcher);\n}\n\n<\/code><\/pre>\n<p>\u4fee\u6539DefinitionRealm\u7c7b\u7684\u8ba4\u8bc1doGetAuthenticationInfo\u65b9\u6cd5\u5982\u4e0b<\/p>\n<pre><code class=\"language-java line-numbers\">    \/**\n     * @Description \u8ba4\u8bc1\u63a5\u53e3\n     * @param token \u4f20\u9012\u767b\u5f55token\n     * @return\n     *\/\n@Override\nprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {\n    \/\/\u4eceAuthenticationToken\u4e2d\u83b7\u5f97\u767b\u5f55\u540d\u79f0\n    String loginName = (String) token.getPrincipal();\n    SecurityService securityService = new SecurityServiceImpl();\n    Map&lt;String, String&gt; map = securityService.findPasswordByLoginName(loginName);\n    if (map.isEmpty()){\n        throw new UnknownAccountException(\"\u8d26\u6237\u4e0d\u5b58\u5728\");\n    }\n    String salt = map.get(\"salt\");\n    String password = map.get(\"password\");\n    \/\/\u4f20\u9012\u8d26\u53f7\u548c\u5bc6\u7801:\u53c2\u65701\uff1a\u7f13\u5b58\u5bf9\u8c61\uff0c\u53c2\u65702\uff1a\u660e\u6587\u5bc6\u7801\uff0c\u53c2\u6570\u4e09\uff1a\u5b57\u8282salt,\u53c2\u65704\uff1a\u5f53\u524dDefinitionRealm\u540d\u79f0\n    return  new SimpleAuthenticationInfo(loginName,password, ByteSource.Util.bytes(salt),getName());\n}\n\n<\/code><\/pre>\n<h4>\u30105\u3011\u6d4b\u8bd5<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580282597761.png\" alt=\"1580282597761\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580282723275.png\" alt=\"1580282723275\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580282829816.png\" alt=\"1580282829816\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580282869315.png\" alt=\"1580282869315\" \/><\/p>\n<h3>5\u3001\u8eab\u4efd\u6388\u6743<\/h3>\n<h4>\u30101\u3011\u57fa\u672c\u6d41\u7a0b<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580284991759.png\" alt=\"1580284991759\" \/><\/p>\n<p>1\u3001\u9996\u5148\u8c03\u7528Subject.isPermitted\/hasRole\u63a5\u53e3\uff0c\u5176\u4f1a\u59d4\u6258\u7ed9SecurityManager\u3002<\/p>\n<p>2\u3001SecurityManager\u63a5\u7740\u4f1a\u59d4\u6258\u7ed9\u5185\u90e8\u7ec4\u4ef6Authorizer\uff1b<\/p>\n<p>3\u3001Authorizer\u518d\u5c06\u5176\u8bf7\u6c42\u59d4\u6258\u7ed9\u6211\u4eec\u7684Realm\u53bb\u505a\uff1bRealm\u624d\u662f\u771f\u6b63\u5e72\u6d3b\u7684\uff1b<\/p>\n<p>4\u3001Realm\u5c06\u7528\u6237\u8bf7\u6c42\u7684\u53c2\u6570\u5c01\u88c5\u6210\u6743\u9650\u5bf9\u8c61\u3002\u518d\u4ece\u6211\u4eec\u91cd\u5199\u7684doGetAuthorizationInfo\u65b9\u6cd5\u4e2d\u83b7\u53d6\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u8be2\u5230\u7684\u6743\u9650\u96c6\u5408\u3002<\/p>\n<p>5\u3001Realm\u5c06\u7528\u6237\u4f20\u5165\u7684\u6743\u9650\u5bf9\u8c61\uff0c\u4e0e\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u51fa\u6765\u7684\u6743\u9650\u5bf9\u8c61\uff0c\u8fdb\u884c\u4e00\u4e00\u5bf9\u6bd4\u3002\u5982\u679c\u7528\u6237\u4f20\u5165\u7684\u6743\u9650\u5bf9\u8c61\u5728\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u51fa\u6765\u7684\u6743\u9650\u5bf9\u8c61\u4e2d\uff0c\u5219\u8fd4\u56detrue\uff0c\u5426\u5219\u8fd4\u56defalse\u3002<\/p>\n<p>\u8fdb\u884c\u6388\u6743\u64cd\u4f5c\u7684\u524d\u63d0\uff1a\u7528\u6237\u5fc5\u987b\u901a\u8fc7\u8ba4\u8bc1\u3002<\/p>\n<p>\u5728\u771f\u5b9e\u7684\u9879\u76ee\u4e2d\uff0c\u89d2\u8272\u4e0e\u6743\u9650\u90fd\u5b58\u653e\u5728\u6570\u636e\u5e93\u4e2d\u3002\u4e3a\u4e86\u5feb\u901f\u4e0a\u624b\uff0c\u6211\u4eec\u5148\u521b\u5efa\u4e00\u4e2a\u81ea\u5b9a\u4e49DefinitionRealm\uff0c\u6a21\u62df\u5b83\u5df2\u7ecf\u767b\u5f55\u6210\u529f\u3002\u76f4\u63a5\u8fd4\u56de\u4e00\u4e2a\u767b\u5f55\u9a8c\u8bc1\u51ed\u8bc1\uff0c\u544a\u8bc9Shiro\u6846\u67b6\uff0c\u6211\u4eec\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u8be2\u51fa\u6765\u7684\u5bc6\u7801\u662f\u4e5f\u662f\u5c31\u662f\u4f60\u8f93\u5165\u7684\u5bc6\u7801\u3002\u6240\u4ee5\uff0c\u4e0d\u7ba1\u7528\u6237\u8f93\u5165\u4ec0\u4e48\uff0c\u672c\u6b21\u767b\u5f55\u9a8c\u8bc1\u90fd\u662f\u901a\u8fc7\u7684\u3002<\/p>\n<pre><code class=\"language-java line-numbers\">  \/**\n     * @Description \u8ba4\u8bc1\u63a5\u53e3\n     * @param token \u4f20\u9012\u767b\u5f55token\n     * @return\n     *\/\n@Override\nprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {\n    \/\/\u4eceAuthenticationToken\u4e2d\u83b7\u5f97\u767b\u5f55\u540d\u79f0\n    String loginName = (String) token.getPrincipal();\n    SecurityService securityService = new SecurityServiceImpl();\n    Map&lt;String, String&gt; map = securityService.findPasswordByLoginName(loginName);\n    if (map.isEmpty()){\n        throw new UnknownAccountException(\"\u8d26\u6237\u4e0d\u5b58\u5728\");\n    }\n    String salt = map.get(\"salt\");\n    String password = map.get(\"password\");\n    \/\/\u4f20\u9012\u8d26\u53f7\u548c\u5bc6\u7801:\u53c2\u65701\uff1a\u7528\u6237\u8ba4\u8bc1\u51ed\u8bc1\u4fe1\u606f\uff0c\u53c2\u65702\uff1a\u660e\u6587\u5bc6\u7801\uff0c\u53c2\u6570\u4e09\uff1a\u5b57\u8282salt,\u53c2\u65704\uff1a\u5f53\u524dDefinitionRealm\u540d\u79f0\n    return  new SimpleAuthenticationInfo(loginName,password, ByteSource.Util.bytes(salt),getName());\n}\n\n<\/code><\/pre>\n<p>\u597d\u4e86\uff0c\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u8981\u91cd\u5199\u6211\u4eec\u672c\u5c0f\u8282\u7684\u6838\u5fc3\u65b9\u6cd5\u4e86\u3002\u5728DefinitionRealm\u4e2d\u627e\u5230\u4e0b\u5217\u65b9\u6cd5\uff1a<\/p>\n<pre><code class=\"language-java line-numbers\">@Override\nprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n    return null;\n}\n\n<\/code><\/pre>\n<p>\u6b64\u65b9\u6cd5\u7684\u4f20\u5165\u7684\u53c2\u6570PrincipalCollection  principals\uff0c\u662f\u4e00\u4e2a\u5305\u88c5\u5bf9\u8c61\uff0c\u5b83\u8868\u793a&#8221;\u7528\u6237\u8ba4\u8bc1\u51ed\u8bc1\u4fe1\u606f&#8221;\u3002\u5305\u88c5\u7684\u662f\u8c01\u5462\uff1f\u6ca1\u9519\uff0c\u5c31\u662f\u8ba4\u8bc1doGetAuthenticationInfo\uff08\uff09\u65b9\u6cd5\u7684\u8fd4\u56de\u503c\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570loginName\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u5305\u88c5\u5bf9\u8c61\u7684getPrimaryPrincipal\uff08\uff09\u65b9\u6cd5\u62ff\u5230\u6b64\u503c,\u7136\u540e\u518d\u4ece\u6570\u636e\u5e93\u4e2d\u62ff\u5230\u5bf9\u5e94\u7684\u89d2\u8272\u548c\u8d44\u6e90\uff0c\u6784\u5efaSimpleAuthorizationInfo\u3002<\/p>\n<pre><code class=\"language-java line-numbers\">\/**\n     * @Description \u6388\u6743\u65b9\u6cd5\n     *\/\n@Override\nprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n    \/\/\u62ff\u5230\u7528\u6237\u8ba4\u8bc1\u51ed\u8bc1\u4fe1\u606f\n    String loginName = (String) principals.getPrimaryPrincipal();\n    \/\/\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u8be2\u5bf9\u5e94\u7684\u89d2\u8272\u548c\u8d44\u6e90\n    SecurityService securityService = new SecurityServiceImpl();\n    List&lt;String&gt; roles = securityService.findRoleByloginName(loginName);\n    List&lt;String&gt; permissions = securityService.findPermissionByloginName(loginName);\n    \/\/\u6784\u5efa\u8d44\u6e90\u6821\u9a8c\n    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();\n    authorizationInfo.addRoles(roles);\n    authorizationInfo.addStringPermissions(permissions);\n    return authorizationInfo;\n}\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u6848\u4f8b\u6f14\u793a<\/h4>\n<h5>\u30102.1\u3011\u9700\u6c42<\/h5>\n<pre><code class=\"line-numbers\">1\u3001\u5b9e\u73b0doGetAuthorizationInfo\u65b9\u6cd5\u5b9e\u73b0\u9274\u6743\n2\u3001\u4f7f\u7528subject\u7c7b\u5b9e\u73b0\u6743\u9650\u7684\u6821\u9a8c\n\n<\/code><\/pre>\n<h5>\u30102.2\u3011\u5b9e\u73b0<\/h5>\n<h6>\u30102.2.1\u3011\u521b\u5efa\u9879\u76ee<\/h6>\n<p>\u62f7\u8d1dshiro-day01-05-ciphertext-realm\u65b0\u5efashiro-day01-06-authentication-realm<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580367506898.png\" alt=\"1580367506898\" \/><\/p>\n<h6>\u30102.2.2\u3011\u7f16\u5199SecurityService<\/h6>\n<p>\u5728SecurityService\u4e2d\u6dfb\u52a0<\/p>\n<pre><code class=\"language-java line-numbers\">    \/**\n     * @Description \u67e5\u627e\u89d2\u8272\u6309\u7528\u6237\u767b\u5f55\u540d\n     * @param  loginName \u767b\u5f55\u540d\u79f0\n     * @return\n     *\/\nList&lt;String&gt; findRoleByloginName(String loginName);\n\n    \/**\n     * @Description \u67e5\u627e\u8d44\u6e90\u6309\u7528\u6237\u767b\u5f55\u540d\n     * @param  loginName \u767b\u5f55\u540d\u79f0\n     * @return\n     *\/\nList&lt;String&gt;  findPermissionByloginName(String loginName);\n\n<\/code><\/pre>\n<p>SecurityServiceImpl\u6dfb\u52a0\u5b9e\u73b0<\/p>\n<pre><code class=\"language-java line-numbers\">@Override\npublic List&lt;String&gt; findRoleByloginName(String loginName) {\n    List&lt;String&gt; list = new ArrayList&lt;&gt;();\n    list.add(\"admin\");\n    list.add(\"dev\");\n    return list;\n}\n\n@Override\npublic List&lt;String&gt;  findPermissionByloginName(String loginName) {\n    List&lt;String&gt; list = new ArrayList&lt;&gt;();\n    list.add(\"order:add\");\n    list.add(\"order:list\");\n    list.add(\"order:del\");\n    return list;\n}\n\n<\/code><\/pre>\n<h6>\u30102.2.3\u3011\u7f16\u5199DefinitionRealm<\/h6>\n<p>\u5728DefinitionRealm\u4e2d\u4fee\u6539doGetAuthorizationInfo\u65b9\u6cd5\u5982\u4e0b<\/p>\n<pre><code class=\"language-java line-numbers\">\/**\n  * @Description \u6388\u6743\u65b9\u6cd5\n  *\/\n@Override\nprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n    \/\/\u62ff\u5230\u7528\u6237\u8ba4\u8bc1\u51ed\u8bc1\u4fe1\u606f\n    String loginName = (String) principals.getPrimaryPrincipal();\n    \/\/\u4ece\u6570\u636e\u5e93\u4e2d\u67e5\u8be2\u5bf9\u5e94\u7684\u89d2\u8272\u548c\u8d44\u6e90\n    SecurityService securityService = new SecurityServiceImpl();\n    List&lt;String&gt; roles = securityService.findRoleByloginName(loginName);\n    List&lt;String&gt; permissions = securityService.findPermissionByloginName(loginName);\n    \/\/\u6784\u5efa\u8d44\u6e90\u6821\u9a8c\n    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();\n    authorizationInfo.addRoles(roles);\n    authorizationInfo.addStringPermissions(permissions);\n    return authorizationInfo;\n}\n\n<\/code><\/pre>\n<h6>\u30102.2.4\u3011\u7f16\u5199HelloShiro<\/h6>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.config.IniSecurityManagerFactory;\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.util.Factory;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n\/**\n * @Description\uff1ashiro\u7684\u7b2c\u4e00\u4e2a\u4f8b\u5b50\n *\/\npublic class HelloShiro {\n\n\n    @Test\n    public void testPermissionRealm() {\n        Subject subject = shiroLogin(\"jay\", \"123\");\n        \/\/\u5224\u65ad\u7528\u6237\u662f\u5426\u5df2\u7ecf\u767b\u5f55\n        System.out.println(\"\u662f\u5426\u767b\u5f55\u6210\u529f\uff1a\" + subject.isAuthenticated());\n\n        \/\/---------\u68c0\u67e5\u5f53\u524d\u7528\u6237\u7684\u89d2\u8272\u4fe1\u606f------------\n        System.out.println(\"\u662f\u5426\u6709\u7ba1\u7406\u5458\u89d2\u8272\uff1a\"+subject.hasRole(\"admin\"));\n        \/\/---------\u5982\u679c\u5f53\u524d\u7528\u6237\u6709\u6b64\u89d2\u8272\uff0c\u65e0\u8fd4\u56de\u503c\u3002\u82e5\u6ca1\u6709\u6b64\u6743\u9650\uff0c\u5219\u629b UnauthorizedException------------\n        try {\n            subject.checkRole(\"coder\");\n            System.out.println(\"\u6709coder\u89d2\u8272\");\n        }catch (Exception e){\n            System.out.println(\"\u6ca1\u6709coder\u89d2\u8272\");\n        }\n\n        \/\/---------\u68c0\u67e5\u5f53\u524d\u7528\u6237\u7684\u6743\u9650\u4fe1\u606f------------\n        System.out.println(\"\u662f\u5426\u6709\u67e5\u770b\u8ba2\u5355\u5217\u8868\u8d44\u6e90\uff1a\"+subject.isPermitted(\"order:list\"));\n        \/\/---------\u5982\u679c\u5f53\u524d\u7528\u6237\u6709\u6b64\u6743\u9650\uff0c\u65e0\u8fd4\u56de\u503c\u3002\u82e5\u6ca1\u6709\u6b64\u6743\u9650\uff0c\u5219\u629b UnauthorizedException------------\n        try {\n            subject.checkPermissions(\"order:add\", \"order:del\");\n            System.out.println(\"\u6709\u6dfb\u52a0\u548c\u5220\u9664\u8ba2\u5355\u8d44\u6e90\");\n        }catch (Exception e){\n            System.out.println(\"\u6ca1\u6709\u6709\u6dfb\u52a0\u548c\u5220\u9664\u8ba2\u5355\u8d44\u6e90\");\n        }\n\n    }\n\n\n    \/**\n     * @Description \u767b\u5f55\u65b9\u6cd5\n     *\/\n    private Subject shiroLogin(String loginName,String password) {\n        \/\/\u5bfc\u5165\u6743\u9650ini\u6587\u4ef6\u6784\u5efa\u6743\u9650\u5de5\u5382\n        Factory&lt;SecurityManager&gt; factory = new IniSecurityManagerFactory(\"classpath:shiro.ini\");\n        \/\/\u5de5\u5382\u6784\u5efa\u5b89\u5168\u7ba1\u7406\u5668\n        SecurityManager securityManager = factory.getInstance();\n        \/\/\u4f7f\u7528SecurityUtils\u5de5\u5177\u751f\u6548\u5b89\u5168\u7ba1\u7406\u5668\n        SecurityUtils.setSecurityManager(securityManager);\n        \/\/\u4f7f\u7528SecurityUtils\u5de5\u5177\u83b7\u5f97\u4e3b\u4f53\n        Subject subject = SecurityUtils.getSubject();\n        \/\/\u6784\u5efa\u8d26\u53f7token\n        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginName, password);\n        \/\/\u767b\u5f55\u64cd\u4f5c\n        subject.login(usernamePasswordToken);\n        return subject;\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30102.3\u3011\u6388\u6743\u6e90\u7801\u8ffd\u8e2a<\/h5>\n<p>\uff081\uff09\u5ba2\u6237\u7aef\u8c03\u7528 subject.hasRole(&#8220;admin&#8221;)\uff0c\u5224\u65ad\u5f53\u524d\u7528\u6237\u662f\u5426\u6709&#8221;admin&#8221;\u89d2\u8272\u6743\u9650\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580368931926.png\" alt=\"1580368931926\" \/><\/p>\n<p>(2\uff09Subject\u95e8\u9762\u5bf9\u8c61\u63a5\u6536\u5230\u8981\u88ab\u9a8c\u8bc1\u7684\u89d2\u8272\u4fe1\u606f&#8221;admin&#8221;\uff0c\u5e76\u5c06\u5176\u59d4\u6258\u7ed9securityManager\u4e2d\u9a8c\u8bc1\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580368995672.png\" alt=\"1580368995672\" \/><\/p>\n<p>(3\uff09securityManager\u5c06\u9a8c\u8bc1\u8bf7\u6c42\u518d\u6b21\u59d4\u6258\u7ed9\u5185\u90e8\u7684\u5c0f\u5f1f\uff1a\u5185\u90e8\u7ec4\u4ef6Authorizer authorizer<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580369087293.png\" alt=\"1580369087293\" \/><\/p>\n<p>(4)\u5185\u90e8\u5c0f\u5f1fauthorizer\u4e5f\u662f\u4e2a\u6df7\u5b50\uff0c\u5c06\u5176\u59d4\u6258\u7ed9\u4e86\u6211\u4eec\u81ea\u5b9a\u4e49\u7684Realm\u53bb\u505a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580369205937.png\" alt=\"1580369205937\" \/><\/p>\n<p>\uff085\uff09 \u5148\u62ff\u5230PrincipalCollection principal\u5bf9\u8c61\uff0c\u540c\u65f6\u4f20\u5165\u6821\u9a8c\u7684\u89d2\u8272\u5faa\u73af\u6821\u9a8c,\u5faa\u73af\u4e2d\u5148\u521b\u5efa\u9274\u6743\u4fe1\u606f<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580369895496.png\" alt=\"1580369895496\" \/><\/p>\n<p>\uff086\uff09\u5148\u770b\u7f13\u5b58\u4e2d\u662f\u5426\u5df2\u7ecf\u6709\u9274\u6743\u4fe1\u606f<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580369979541.png\" alt=\"1580369979541\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580370086849.png\" alt=\"1580370086849\" \/><\/p>\n<p>(7)\u90fd\u662f\u4e00\u7fa4\u61d2\u8d27\uff01\uff01\u6700\u540e\u5e72\u6d3b\u7684\u8fd8\u662f\u6211\u8fd9\u4e2a\u7334\u5b50\uff01<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580370172670.png\" alt=\"1580370172670\" \/><\/p>\n<h4>\u30103\u3011\u5c0f\u7ed3<\/h4>\n<pre><code class=\"line-numbers\">1\u3001\u9274\u6743\u9700\u8981\u5b9e\u73b0doGetAuthorizationInfo\u65b9\u6cd5\n2\u3001\u9274\u6743\u4f7f\u7528\u95e8\u9762subject\u4e2d\u65b9\u6cd5\u8fdb\u884c\u9274\u6743\n    \u4ee5check\u5f00\u5934\u7684\u4f1a\u629b\u51fa\u5f02\u5e38\n    \u4ee5is\u548chas\u5f00\u5934\u4f1a\u8fd4\u56de\u5e03\u5c14\u503c\n\n<\/code><\/pre>\n<h2>\u7b2c\u56db\u7ae0 Web\u9879\u76ee\u96c6\u6210Shiro<\/h2>\n<h3>1\u3001Web\u96c6\u6210\u539f\u7406\u5206\u6790<\/h3>\n<h4>\u30101\u3011web\u96c6\u6210\u7684\u914d\u7f6e<\/h4>\n<p>\u8fd8\u8bb0\u5f97\u5417\uff0c\u4ee5\u524d\u6211\u4eec\u5728\u6ca1\u6709\u4e0eWEB\u73af\u5883\u8fdb\u884c\u96c6\u6210\u7684\u65f6\u5019\uff0c\u4e3a\u4e86\u751f\u6210SecurityManager\u5bf9\u8c61\uff0c\u662f\u901a\u8fc7\u624b\u52a8\u8bfb\u53d6\u914d\u7f6e\u6587\u4ef6\u751f\u6210\u5de5\u5382\u5bf9\u8c61\uff0c\u518d\u901a\u8fc7\u5de5\u5382\u5bf9\u8c61\u83b7\u53d6\u5230SecurityManager\u7684\u3002\u5c31\u50cf\u4e0b\u9762\u4ee3\u7801\u5c55\u793a\u7684\u90a3\u6837<\/p>\n<pre><code class=\"language-java line-numbers\"> \/**\n   * @Description \u767b\u5f55\u65b9\u6cd5\n   *\/\nprivate Subject shiroLogin(String loginName,String password) {\n    \/\/\u5bfc\u5165\u6743\u9650ini\u6587\u4ef6\u6784\u5efa\u6743\u9650\u5de5\u5382\n    Factory&lt;SecurityManager&gt; factory = new IniSecurityManagerFactory(\"classpath:shiro.ini\");\n    \/\/\u5de5\u5382\u6784\u5efa\u5b89\u5168\u7ba1\u7406\u5668\n    SecurityManager securityManager = factory.getInstance();\n    \/\/\u4f7f\u7528SecurityUtils\u5de5\u5177\u751f\u6548\u5b89\u5168\u7ba1\u7406\u5668\n    SecurityUtils.setSecurityManager(securityManager);\n    \/\/\u4f7f\u7528SecurityUtils\u5de5\u5177\u83b7\u5f97\u4e3b\u4f53\n    Subject subject = SecurityUtils.getSubject();\n    \/\/\u6784\u5efa\u8d26\u53f7token\n    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginName, password);\n    \/\/\u767b\u5f55\u64cd\u4f5c\n    subject.login(usernamePasswordToken);\n    return subject;\n}\n\n<\/code><\/pre>\n<p>\u4e0d\u8fc7\uff0c\u73b0\u5728\u6211\u4eec\u65e2\u7136\u8bf4\u8981\u4e0eWEB\u96c6\u6210\uff0c\u90a3\u4e48\u9996\u5148\u8981\u505a\u7684\u4e8b\u60c5\u5c31\u662f\u628a\u6211\u4eec\u7684shiro.ini\u8fd9\u4e2a\u914d\u7f6e\u6587\u4ef6\u4ea4\u4ed8\u5230WEB\u73af\u5883\u4e2d\uff0c\u5b9a\u4e49shiro.ini\u6587\u4ef6\u5982\u4e0b<\/p>\n<pre><code class=\"language-ini line-numbers\">#\u58f0\u660e\u81ea\u5b9a\u4e49\u7684realm\uff0c\u4e14\u4e3a\u5b89\u5168\u7ba1\u7406\u5668\u6307\u5b9arealms\n[main]\ndefinitionRealm=com.itheima.shiro.realm.DefinitionRealm\nsecurityManager.realms=$definitionRealm\n\n<\/code><\/pre>\n<h5>\u30101.1\u3011\u65b0\u5efa\u9879\u76ee<\/h5>\n<p>\u65b0\u5efaweb\u9879\u76eeshiro-day01-07web,\u5176\u4e2drealm\u3001service\u3001resources\u5185\u5bb9\u4eceshiro-day01-06authentication-realm\u4e2d\u62f7\u8d1d\u5373\u53ef<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580538893171.png\" alt=\"1580538893171\" \/><\/p>\n<h5>\u30101.2\u3011pom.xml\u914d\u7f6e<\/h5>\n<pre data-language=XML><code class=\"language-markup line-numbers\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n  xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n\n  &lt;groupId&gt;com.itheima.shiro&lt;\/groupId&gt;\n  &lt;artifactId&gt;shiro-day01-07web&lt;\/artifactId&gt;\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\n  &lt;packaging&gt;war&lt;\/packaging&gt;\n\n  &lt;name&gt;shiro-day01-07web Maven Webapp&lt;\/name&gt;\n  &lt;!-- FIXME change it to the project's website --&gt;\n  &lt;url&gt;http:\/\/www.example.com&lt;\/url&gt;\n\n  &lt;dependencies&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;commons-logging&lt;\/groupId&gt;\n      &lt;artifactId&gt;commons-logging&lt;\/artifactId&gt;\n      &lt;version&gt;1.1.3&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.apache.shiro&lt;\/groupId&gt;\n      &lt;artifactId&gt;shiro-core&lt;\/artifactId&gt;\n      &lt;version&gt;1.3.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.apache.shiro&lt;\/groupId&gt;\n      &lt;artifactId&gt;shiro-web&lt;\/artifactId&gt;\n      &lt;version&gt;1.3.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;junit&lt;\/groupId&gt;\n      &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n      &lt;version&gt;4.11&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n  &lt;\/dependencies&gt;\n\n  &lt;build&gt;\n    &lt;plugins&gt;\n      &lt;!-- tomcat7\u63d2\u4ef6,\u547d\u4ee4\uff1a mvn tomcat7:run -DskipTests --&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.tomcat.maven&lt;\/groupId&gt;\n        &lt;artifactId&gt;tomcat7-maven-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;2.2&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;uriEncoding&gt;utf-8&lt;\/uriEncoding&gt;\n          &lt;port&gt;8080&lt;\/port&gt;\n          &lt;path&gt;\/platform&lt;\/path&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n\n      &lt;!-- compiler\u63d2\u4ef6, \u8bbe\u5b9aJDK\u7248\u672c --&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n        &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;3.1&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;source&gt;8&lt;\/source&gt;\n          &lt;target&gt;8&lt;\/target&gt;\n          &lt;showWarnings&gt;true&lt;\/showWarnings&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n    &lt;\/plugins&gt;\n  &lt;\/build&gt;\n&lt;\/project&gt;\n\n\n<\/code><\/pre>\n<h5>\u30101.3\u3011web.xml\u914d\u7f6e<\/h5>\n<pre data-language=XML><code class=\"language-markup line-numbers\">&lt;web-app xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n         xmlns=\"http:\/\/java.sun.com\/xml\/ns\/javaee\"\n         xsi:schemaLocation=\"http:\/\/java.sun.com\/xml\/ns\/javaee http:\/\/java.sun.com\/xml\/ns\/javaee\/web-app_3_0.xsd\"\n         version=\"3.0\"&gt;\n  &lt;display-name&gt;shiro-day01-07web&lt;\/display-name&gt;\n\n  &lt;!-- \u521d\u59cb\u5316SecurityManager\u5bf9\u8c61\u6240\u9700\u8981\u7684\u73af\u5883--&gt;\n  &lt;context-param&gt;\n    &lt;param-name&gt;shiroEnvironmentClass&lt;\/param-name&gt;\n    &lt;param-value&gt;org.apache.shiro.web.env.IniWebEnvironment&lt;\/param-value&gt;\n  &lt;\/context-param&gt;\n\n  &lt;!-- \u6307\u5b9aShiro\u7684\u914d\u7f6e\u6587\u4ef6\u7684\u4f4d\u7f6e --&gt;\n  &lt;context-param&gt;\n    &lt;param-name&gt;shiroConfigLocations&lt;\/param-name&gt;\n    &lt;param-value&gt;classpath:shiro.ini&lt;\/param-value&gt;\n  &lt;\/context-param&gt;\n\n  &lt;!-- \u76d1\u542c\u670d\u52a1\u5668\u542f\u52a8\u65f6\uff0c\u521b\u5efashiro\u7684web\u73af\u5883\u3002\n       \u5373\u52a0\u8f7dshiroEnvironmentClass\u53d8\u91cf\u6307\u5b9a\u7684IniWebEnvironment\u7c7b--&gt;\n  &lt;listener&gt;\n    &lt;listener-class&gt;org.apache.shiro.web.env.EnvironmentLoaderListener&lt;\/listener-class&gt;\n  &lt;\/listener&gt;\n\n  &lt;!-- shiro\u7684l\u8fc7\u6ee4\u5165\u53e3\uff0c\u8fc7\u6ee4\u4e00\u5207\u8bf7\u6c42 --&gt;\n  &lt;filter&gt;\n    &lt;filter-name&gt;shiroFilter&lt;\/filter-name&gt;\n    &lt;filter-class&gt;org.apache.shiro.web.servlet.ShiroFilter&lt;\/filter-class&gt;\n  &lt;\/filter&gt;\n  &lt;filter-mapping&gt;\n    &lt;filter-name&gt;shiroFilter&lt;\/filter-name&gt;\n    &lt;!-- \u8fc7\u6ee4\u6240\u6709\u8bf7\u6c42 --&gt;\n    &lt;url-pattern&gt;\/*&lt;\/url-pattern&gt;\n  &lt;\/filter-mapping&gt;\n\n&lt;\/web-app&gt;\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011SecurityManager\u5bf9\u8c61\u521b\u5efa<\/h4>\n<p>\u4e0a\u9762\u6211\u4eec\u96c6\u6210shiro\u5230web\u9879\u76ee\u4e86\uff0c\u4e0b\u9762\u6211\u4eec\u6765\u8ffd\u8e2a\u4e0b\u6e90\u7801\uff0c\u770b\u4e0bSecurityManager\u5bf9\u8c61\u662f\u5982\u4f55\u521b\u5efa\u7684<\/p>\n<p>\uff081\uff09\u6211\u542f\u52a8\u4e86\u670d\u52a1\u5668\uff0c\u76d1\u542c\u5668\u6355\u83b7\u5230\u4e86\u670d\u52a1\u5668\u542f\u52a8\u4e8b\u4ef6\u3002\u6211\u73b0\u5728\u6240\u5904\u7684\u4f4d\u7f6eEnvironmentLoaderListener\u76d1\u542c\u5668\u7684\u5165\u53e3\u5904<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580539365062.png\" alt=\"1580539365062\" \/><\/p>\n<p>\uff082\uff09\u8fdb\u5165\u65b9\u6cd5\u5185\u67e5\u770b\uff0c\u5b83\u5148\u6839\u636e\u6211\u4eec\u7684shiroEnvironmentClass\u53d8\u91cf\u7684\u503corg.apache.shiro.web.env.IniWebEnvironment\uff0c\u521d\u59cb\u5316\u4e00\u4e2ashiro\u73af\u5883\u5bf9\u8c61<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580539658469.png\" alt=\"1580539658469\" \/><\/p>\n<p>\uff083\uff09\u6700\u540e\u5728\u521b\u5efa\u4e00\u4e2aSecurityManager\u5bf9\u8c61\uff0c\u518d\u5c06\u5176\u7ed1\u5b9a\u5230\u521a\u624d\u901a\u8fc7\u5b57\u8282\u7801\u521b\u5efa\u7684Shiro\u73af\u5883\u5bf9\u8c61\u4e2d<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580540126770.png\" alt=\"1580540126770\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580540180066.png\" alt=\"1580540180066\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580540218911.png\" alt=\"1580540218911\" \/><\/p>\n<p>\u5230\u8fd9\u6765SecurityManager\u5c31\u5b8c\u6210\u4e86\u521d\u59cb\u5316<\/p>\n<h3>2\u3001Shiro\u9ed8\u8ba4\u8fc7\u6ee4\u5668<\/h3>\n<p>Shiro\u5185\u7f6e\u4e86\u5f88\u591a\u9ed8\u8ba4\u7684\u8fc7\u6ee4\u5668\uff0c\u6bd4\u5982\u8eab\u4efd\u9a8c\u8bc1\u3001\u6388\u6743\u7b49\u76f8\u5173\u7684\u3002\u9ed8\u8ba4\u8fc7\u6ee4\u5668\u53ef\u4ee5\u53c2\u8003org.apache.shiro.web.filter.mgt.DefaultFilter\u4e2d\u7684\u679a\u4e3e\u8fc7\u6ee4\u5668<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580542509773.png\" alt=\"1580542509773\" \/><\/p>\n<h4>\u30101\u3011\u8ba4\u8bc1\u76f8\u5173<\/h4>\n<table>\n<thead>\n<tr>\n<th>\u8fc7\u6ee4\u5668<\/th>\n<th>\u8fc7\u6ee4\u5668\u7c7b<\/th>\n<th>\u8bf4\u660e<\/th>\n<th>\u9ed8\u8ba4<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>authc<\/td>\n<td>FormAuthenticationFilter<\/td>\n<td>\u57fa\u4e8e\u8868\u5355\u7684\u8fc7\u6ee4\u5668\uff1b\u5982\u201c\/**=authc\u201d\uff0c\u5982\u679c\u6ca1\u6709\u767b\u5f55\u4f1a\u8df3\u5230\u76f8\u5e94\u7684\u767b\u5f55\u9875\u9762\u767b\u5f55<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<tr>\n<td>logout<\/td>\n<td>LogoutFilter<\/td>\n<td>\u9000\u51fa\u8fc7\u6ee4\u5668\uff0c\u4e3b\u8981\u5c5e\u6027\uff1aredirectUrl\uff1a\u9000\u51fa\u6210\u529f\u540e\u91cd\u5b9a\u5411\u7684\u5730\u5740\uff0c\u5982\u201c\/logout=logout\u201d<\/td>\n<td>\/<\/td>\n<\/tr>\n<tr>\n<td>anon<\/td>\n<td>AnonymousFilter<\/td>\n<td>\u533f\u540d\u8fc7\u6ee4\u5668\uff0c\u5373\u4e0d\u9700\u8981\u767b\u5f55\u5373\u53ef\u8bbf\u95ee\uff1b\u4e00\u822c\u7528\u4e8e\u9759\u6001\u8d44\u6e90\u8fc7\u6ee4\uff1b\u793a\u4f8b\u201c\/static\/**=anon\u201d<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4>\u30102\u3011\u6388\u6743\u76f8\u5173<\/h4>\n<table>\n<thead>\n<tr>\n<th>\u8fc7\u6ee4\u5668<\/th>\n<th>\u8fc7\u6ee4\u5668\u7c7b<\/th>\n<th>\u8bf4\u660e<\/th>\n<th>\u9ed8\u8ba4<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>roles<\/td>\n<td>RolesAuthorizationFilter<\/td>\n<td>\u89d2\u8272\u6388\u6743\u62e6\u622a\u5668\uff0c\u9a8c\u8bc1\u7528\u6237\u662f\u5426\u62e5\u6709\u6240\u6709\u89d2\u8272\uff1b\u4e3b\u8981\u5c5e\u6027\uff1a loginUrl\uff1a\u767b\u5f55\u9875\u9762\u5730\u5740\uff08\/login.jsp\uff09\uff1bunauthorizedUrl\uff1a\u672a\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684\u5730\u5740\uff1b\u793a\u4f8b\u201c\/admin\/**=roles[admin]\u201d<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<tr>\n<td>perms<\/td>\n<td>PermissionsAuthorizationFilter<\/td>\n<td>\u6743\u9650\u6388\u6743\u62e6\u622a\u5668\uff0c\u9a8c\u8bc1\u7528\u6237\u662f\u5426\u62e5\u6709\u6240\u6709\u6743\u9650\uff1b\u5c5e\u6027\u548croles\u4e00\u6837\uff1b\u793a\u4f8b\u201c\/user\/**=perms[&#8220;user:create&#8221;]\u201d<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<tr>\n<td>port<\/td>\n<td>PortFilter<\/td>\n<td>\u7aef\u53e3\u62e6\u622a\u5668\uff0c\u4e3b\u8981\u5c5e\u6027\uff1aport\uff0880\uff09\uff1a\u53ef\u4ee5\u901a\u8fc7\u7684\u7aef\u53e3\uff1b\u793a\u4f8b\u201c\/test= port[80]\u201d\uff0c\u5982\u679c\u7528\u6237\u8bbf\u95ee\u8be5\u9875\u9762\u662f\u975e80\uff0c\u5c06\u81ea\u52a8\u5c06\u8bf7\u6c42\u7aef\u53e3\u6539\u4e3a80\u5e76\u91cd\u5b9a\u5411\u5230\u8be580\u7aef\u53e3\uff0c\u5176\u4ed6\u8def\u5f84\/\u53c2\u6570\u7b49\u90fd\u4e00\u6837<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<tr>\n<td>rest<\/td>\n<td>HttpMethodPermissionFilter<\/td>\n<td>rest\u98ce\u683c\u62e6\u622a\u5668\uff0c\u81ea\u52a8\u6839\u636e\u8bf7\u6c42\u65b9\u6cd5\u6784\u5efa\u6743\u9650\u5b57\u7b26\u4e32\uff08GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create\uff09\u6784\u5efa\u6743\u9650\u5b57\u7b26\u4e32\uff1b\u793a\u4f8b\u201c\/users=rest[user]\u201d\uff0c\u4f1a\u81ea\u52a8\u62fc\u51fa\u201cuser:read,user:create,user:update,user:delete\u201d\u6743\u9650\u5b57\u7b26\u4e32\u8fdb\u884c\u6743\u9650\u5339\u914d\uff08\u6240\u6709\u90fd\u5f97\u5339\u914d\uff0cisPermittedAll\uff09<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<tr>\n<td>ssl<\/td>\n<td>SslFilter<\/td>\n<td>SSL\u62e6\u622a\u5668\uff0c\u53ea\u6709\u8bf7\u6c42\u534f\u8bae\u662fhttps\u624d\u80fd\u901a\u8fc7\uff1b\u5426\u5219\u81ea\u52a8\u8df3\u8f6c\u4f1ahttps\u7aef\u53e3\uff08443\uff09\uff1b\u5176\u4ed6\u548cport\u62e6\u622a\u5668\u4e00\u6837\uff1b<\/td>\n<td>\u65e0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>3\u3001Web\u96c6\u6210\u5b8c\u6574\u6848\u4f8b<\/h3>\n<p>\u57fa\u4e8eshiro-day01-07web\u7ee7\u7eed\u96c6\u6210<\/p>\n<h4>\u30101\u3011\u7f16\u5199pom.xml<\/h4>\n<pre data-language=XML><code class=\"language-markup line-numbers\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n  xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n\n  &lt;groupId&gt;com.itheima.shiro&lt;\/groupId&gt;\n  &lt;artifactId&gt;shiro-day01-07web&lt;\/artifactId&gt;\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\n  &lt;packaging&gt;war&lt;\/packaging&gt;\n\n  &lt;name&gt;shiro-day01-07web Maven Webapp&lt;\/name&gt;\n  &lt;!-- FIXME change it to the project's website --&gt;\n  &lt;url&gt;http:\/\/www.example.com&lt;\/url&gt;\n\n  &lt;dependencies&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;commons-logging&lt;\/groupId&gt;\n      &lt;artifactId&gt;commons-logging&lt;\/artifactId&gt;\n      &lt;version&gt;1.1.3&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.apache.shiro&lt;\/groupId&gt;\n      &lt;artifactId&gt;shiro-core&lt;\/artifactId&gt;\n      &lt;version&gt;1.3.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;org.apache.shiro&lt;\/groupId&gt;\n      &lt;artifactId&gt;shiro-web&lt;\/artifactId&gt;\n      &lt;version&gt;1.3.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;junit&lt;\/groupId&gt;\n      &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n      &lt;version&gt;4.11&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;javax.servlet&lt;\/groupId&gt;\n      &lt;artifactId&gt;javax.servlet-api&lt;\/artifactId&gt;\n      &lt;version&gt;3.0.1&lt;\/version&gt;\n      &lt;scope&gt;provided&lt;\/scope&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;jstl&lt;\/groupId&gt;\n      &lt;artifactId&gt;jstl&lt;\/artifactId&gt;\n      &lt;version&gt;1.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;taglibs&lt;\/groupId&gt;\n      &lt;artifactId&gt;standard&lt;\/artifactId&gt;\n      &lt;version&gt;1.1.2&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n  &lt;\/dependencies&gt;\n\n  &lt;build&gt;\n    &lt;plugins&gt;\n      &lt;!-- tomcat7\u63d2\u4ef6,\u547d\u4ee4\uff1a mvn tomcat7:run -DskipTests --&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.tomcat.maven&lt;\/groupId&gt;\n        &lt;artifactId&gt;tomcat7-maven-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;2.2&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;uriEncoding&gt;utf-8&lt;\/uriEncoding&gt;\n          &lt;port&gt;8080&lt;\/port&gt;\n          &lt;path&gt;\/platform&lt;\/path&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n\n      &lt;!-- compiler\u63d2\u4ef6, \u8bbe\u5b9aJDK\u7248\u672c --&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n        &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;3.1&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;source&gt;8&lt;\/source&gt;\n          &lt;target&gt;8&lt;\/target&gt;\n          &lt;showWarnings&gt;true&lt;\/showWarnings&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n    &lt;\/plugins&gt;\n  &lt;\/build&gt;\n&lt;\/project&gt;\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u7f16\u5199shiro.ini\u6587\u4ef6<\/h4>\n<pre><code class=\"language-ini line-numbers\">#\u58f0\u660e\u81ea\u5b9a\u4e49\u7684realm\uff0c\u4e14\u4e3a\u5b89\u5168\u7ba1\u7406\u5668\u6307\u5b9arealms\n[main]\ndefinitionRealm=com.itheima.shiro.realm.DefinitionRealm\nsecurityManager.realms=$definitionRealm\n#\u7528\u6237\u9000\u51fa\u540e\u8df3\u8f6c\u6307\u5b9aJSP\u9875\u9762\nlogout.redirectUrl=\/login.jsp\n#\u82e5\u6ca1\u6709\u767b\u5f55\uff0c\u5219\u88abauthc\u8fc7\u6ee4\u5668\u91cd\u5b9a\u5411\u5230login.jsp\u9875\u9762\nauthc.loginUrl = \/login.jsp\n[urls]\n\/login=anon\n#\u53d1\u9001\/home\u8bf7\u6c42\u9700\u8981\u5148\u767b\u5f55\n\/home= authc\n#\u53d1\u9001\/order\/list\u8bf7\u6c42\u9700\u8981\u5148\u767b\u5f55\n\/order-list = roles[admin]\n#\u63d0\u4ea4\u4ee3\u7801\u9700\u8981order:add\u6743\u9650\n\/order-add = perms[\"order:add\"]\n#\u66f4\u65b0\u4ee3\u7801\u9700\u8981order:del\u6743\u9650\n\/order-del = perms[\"order:del\"]\n#\u53d1\u9001\u9000\u51fa\u8bf7\u6c42\u5219\u7528\u9000\u51fa\u8fc7\u6ee4\u5668\n\/logout = logout\n\n\n<\/code><\/pre>\n<h4>\u30103\u3011\u7f16\u5199LoginService<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service;\n\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\nimport java.lang.management.LockInfo;\n\n\/**\n * @Description\uff1a\u767b\u5f55\u670d\u52a1\n *\/\npublic interface LoginService {\n\n    \/**\n     * @Description \u767b\u5f55\u65b9\u6cd5\n     * @param token \u767b\u5f55\u5bf9\u8c61\n     * @return\n     *\/\n    boolean login(UsernamePasswordToken token);\n\n    \/**\n     * @Description \u767b\u51fa\u65b9\u6cd5\n     *\/\n    void logout();\n}\n\n\n<\/code><\/pre>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.itheima.shiro.service.LoginService;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.subject.Subject;\n\n\n\/**\n * @Description\uff1a\u767b\u5f55\u670d\u52a1\n *\/\npublic class LoginServiceImpl implements LoginService {\n\n    @Override\n    public boolean login(UsernamePasswordToken token) {\n        Subject subject = SecurityUtils.getSubject();\n        try {\n            subject.login(token);\n        }catch (Exception e){\n            return false;\n        }\n        return subject.isAuthenticated();\n    }\n\n    @Override\n    public void logout() {\n        Subject subject = SecurityUtils.getSubject();\n        subject.logout();\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30104\u3011\u7f16\u5199SecurityServiceImpl<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.itheima.shiro.service.SecurityService;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u6743\u9650\u670d\u52a1\u5c42\n *\/\npublic class SecurityServiceImpl implements SecurityService {\n\n    @Override\n    public Map&lt;String,String&gt; findPasswordByLoginName(String loginName) {\n        return DigestsUtil.entryptPassword(\"123\");\n        return map;\n    }\n\n    @Override\n    public List&lt;String&gt; findRoleByloginName(String loginName) {\n        List&lt;String&gt; list = new ArrayList&lt;&gt;();\n        if (\"admin\".equals(loginName)){\n            list.add(\"admin\");\n        }\n        list.add(\"dev\");\n        return list;\n    }\n\n    @Override\n    public List&lt;String&gt;  findPermissionByloginName(String loginName) {\n        List&lt;String&gt; list = new ArrayList&lt;&gt;();\n        if (\"jay\".equals(loginName)){\n            list.add(\"order:list\");\n            list.add(\"order:add\");\n            list.add(\"order:del\");\n        }\n        return list;\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30105\u3011\u6dfb\u52a0web\u5c42\u5185\u5bb9<\/h4>\n<h5>\u30105.1\u3011LoginServlet<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport com.itheima.shiro.service.LoginService;\nimport com.itheima.shiro.service.impl.LoginServiceImpl;\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u767b\u5f55\u65b9\u6cd5\n *\/\n@WebServlet(urlPatterns = \"\/login\")\npublic class LoginServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        \/\/\u83b7\u53d6\u8f93\u5165\u7684\u5e10\u53f7\u5bc6\u7801\n        String username = req.getParameter(\"loginName\");\n        String password = req.getParameter(\"password\");\n        \/\/\u5c01\u88c5\u7528\u6237\u6570\u636e\uff0c\u6210\u4e3aShiro\u80fd\u8ba4\u8bc6\u7684token\u6807\u8bc6\n        UsernamePasswordToken token = new UsernamePasswordToken(username, password);\n        LoginService loginService = new LoginServiceImpl();\n        \/\/\u5c06\u5c01\u88c5\u7528\u6237\u4fe1\u606f\u7684token\u8fdb\u884c\u9a8c\u8bc1\n        boolean isLoginSuccess = loginService.login(token);\n        if (!isLoginSuccess) {\n            \/\/\u91cd\u5b9a\u5411\u5230\u672a\u767b\u5f55\u6210\u529f\u9875\u9762\n            resp.sendRedirect(\"login.jsp\");\n            return;\n        }\n        req.getRequestDispatcher(\"\/home\").forward(req, resp);\n    }\n\n}\n\n<\/code><\/pre>\n<h5>\u30105.2\u3011HomeServlet<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u7cfb\u7edfhome\u9875\u9762\n *\/\n@WebServlet(urlPatterns = \"\/home\")\npublic class HomeServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        req.getRequestDispatcher(\"home.jsp\").forward(req, resp);\n    }\n}\n<\/code><\/pre>\n<h5>\u30105.3\u3011OrderAddServlet<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport com.itheima.shiro.service.LoginService;\nimport com.itheima.shiro.service.impl.LoginServiceImpl;\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u6dfb\u52a0\u9875\u7801\n *\/\n@WebServlet(urlPatterns = \"\/order-add\")\npublic class OrderAddServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        req.getRequestDispatcher(\"order-add.jsp\").forward(req, resp);\n    }\n\n}\n\n<\/code><\/pre>\n<h5>\u30105.4\u3011OrderListServlet<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport com.itheima.shiro.service.LoginService;\nimport com.itheima.shiro.service.impl.LoginServiceImpl;\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u8ba2\u5355\u5217\u8868\n *\/\n@WebServlet(urlPatterns = \"\/order-list\")\npublic class OrderListServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        req.getRequestDispatcher(\"order-list.jsp\").forward(req, resp);\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30105.5\u3011LogoutServlet<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport com.itheima.shiro.service.LoginService;\nimport com.itheima.shiro.service.impl.LoginServiceImpl;\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u767b\u51fa\n *\/\n@WebServlet(urlPatterns = \"\/logout\")\npublic class LogoutServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        LoginService loginService = new LoginServiceImpl();\n        loginService.logout();\n    }\n\n}\n\n<\/code><\/pre>\n<h4>\u30106\u3011\u6dfb\u52a0JSP<\/h4>\n<p>login.jsp\u767b\u5f55\u9875\u9762<\/p>\n<pre data-language=HTML><code class=\"language-markup line-numbers\">&lt;%@ page contentType=\"text\/html;charset=UTF-8\" language=\"java\" %&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\"&gt;\n    &lt;title&gt;Title&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;form method=\"post\" action=\"${pageContext.request.contextPath}\/login\"&gt;\n    &lt;table&gt;\n        &lt;tr&gt;\n            &lt;th&gt;\u767b\u9646\u540d\u79f0&lt;\/th&gt;\n            &lt;td&gt;&lt;input type=\"text\"  name=\"loginName\"&gt;&lt;\/td&gt;\n        &lt;\/tr&gt;\n        &lt;tr&gt;\n            &lt;th&gt;\u5bc6\u7801&lt;\/th&gt;\n            &lt;td&gt;&lt;input type=\"password\" name=\"password\"&gt;&lt;\/td&gt;\n        &lt;\/tr&gt;\n        &lt;tr&gt;\n            &lt;td colspan=\"2\"&gt;\n                &lt;input type=\"submit\" value=\"\u63d0\u4ea4\"\/&gt;\n            &lt;\/td&gt;\n        &lt;\/tr&gt;\n    &lt;\/table&gt;\n\n&lt;\/form&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>home.jsp\u7cfb\u7edf\u9875<\/p>\n<pre data-language=HTML><code class=\"language-markup line-numbers\">&lt;%@ taglib prefix=\"c\" uri=\"http:\/\/java.sun.com\/jsp\/jstl\/core\" %&gt;\n&lt;%@ page contentType=\"text\/html;charset=UTF-8\" language=\"java\" %&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;h6&gt;\n    &lt;a href=\"<span class=\"katex math inline\">{pageContext.request.contextPath}\/logout\"&gt;\u9000\u51fa&lt;\/a&gt;\n    &lt;a href=\"<\/span>{pageContext.request.contextPath}\/order-list\"&gt;\u5217\u8868&lt;\/a&gt;\n    &lt;a href=\"${pageContext.request.contextPath}\/order-add\"&gt;\u6dfb\u52a0&lt;\/a&gt;\n&lt;\/h6&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>order-add.jsp\u8ba2\u5355\u6dfb\u52a0\uff08\u4f2a\u4ee3\u7801\uff09<\/p>\n<pre data-language=HTML><code class=\"language-markup line-numbers\">&lt;%@ page contentType=\"text\/html;charset=UTF-8\" language=\"java\" %&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\"&gt;\n    &lt;title&gt;Title&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n\u6dfb\u52a0\u9875\u9762\n&lt;\/body&gt;\n&lt;\/html&gt;\n\n<\/code><\/pre>\n<p>order-list.jsp\u8ba2\u5355\u5217\u8868<\/p>\n<pre data-language=HTML><code class=\"language-markup line-numbers\">&lt;%@ page contentType=\"text\/html;charset=UTF-8\" language=\"java\" %&gt;\n&lt;%--\u5bfc\u5165jstl\u6807\u7b7e\u5e93--%&gt;\n&lt;%@ taglib prefix=\"c\" uri=\"http:\/\/java.sun.com\/jsp\/jstl\/core\" %&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\"&gt;\n    &lt;title&gt;\u7528\u6237\u5217\u8868jsp\u9875\u9762&lt;\/title&gt;\n    &lt;style&gt;\n        table {border:1px solid #000000}\n        table th{border:1px solid #000000}\n        table td{border:1px solid #000000}\n    &lt;\/style&gt;\n\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;table cellpadding=\"0\" cellspacing=\"0\" width=\"80%\"&gt;\n    &lt;tr&gt;\n        &lt;th&gt;\u7f16\u53f7&lt;\/th&gt;\n        &lt;th&gt;\u516c\u53f8\u540d\u79f0&lt;\/th&gt;\n        &lt;th&gt;\u4fe1\u606f\u6765\u6e90&lt;\/th&gt;\n        &lt;th&gt;\u6240\u5c5e\u884c\u4e1a&lt;\/th&gt;\n        &lt;th&gt;\u7ea7\u522b&lt;\/th&gt;\n        &lt;th&gt;\u8054\u7cfb\u5730\u5740&lt;\/th&gt;\n        &lt;th&gt;\u8054\u7cfb\u7535\u8bdd&lt;\/th&gt;\n    &lt;\/tr&gt;\n    &lt;tr&gt;\n        &lt;td&gt;1&lt;\/td&gt;\n        &lt;td&gt;\u4f20\u667a\u64ad\u5ba2&lt;\/td&gt;\n        &lt;td&gt;\u7f51\u7edc\u8425\u9500&lt;\/td&gt;\n        &lt;td&gt;\u4e92\u8054\u7f51&lt;\/td&gt;\n        &lt;td&gt;\u666e\u901a\u5ba2\u6237&lt;\/td&gt;\n        &lt;td&gt;\u6d25\u5b89\u521b\u610f\u56ed&lt;\/td&gt;\n        &lt;td&gt;0208888887&lt;\/td&gt;\n    &lt;\/tr&gt;\n    &lt;tr&gt;\n        &lt;td&gt;2&lt;\/td&gt;\n        &lt;td&gt;\u9ed1\u9a6c\u7a0b\u5e8f\u5458&lt;\/td&gt;\n        &lt;td&gt;j2ee&lt;\/td&gt;\n        &lt;td&gt;\u4e92\u8054\u7f51&lt;\/td&gt;\n        &lt;td&gt;VIP\u5ba2\u6237&lt;\/td&gt;\n        &lt;td&gt;\u6d25\u5b89\u521b\u610f\u56ed&lt;\/td&gt;\n        &lt;td&gt;0208888887&lt;\/td&gt;\n    &lt;\/tr&gt;\n    &lt;tr&gt;\n        &lt;td&gt;3&lt;\/td&gt;\n        &lt;td&gt;\u9ed1\u9a6c\u7a0b\u5e8f\u5458&lt;\/td&gt;\n        &lt;td&gt;\u5927\u6570\u636e&lt;\/td&gt;\n        &lt;td&gt;\u4e92\u8054\u7f51&lt;\/td&gt;\n        &lt;td&gt;VIP\u5ba2\u6237&lt;\/td&gt;\n        &lt;td&gt;\u6d25\u5b89\u521b\u610f\u56ed&lt;\/td&gt;\n        &lt;td&gt;0208888887&lt;\/td&gt;\n    &lt;\/tr&gt;\n&lt;\/table&gt;\n&lt;\/body&gt;\n\n&lt;\/html&gt;\n\n<\/code><\/pre>\n<h4>\u30107\u3011\u6d4b\u8bd5<\/h4>\n<h5>\u30107.1\u3011\u542f\u52a8<\/h5>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712098325.png\" alt=\"1580712098325\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712149790.png\" alt=\"1580712149790\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712207992.png\" alt=\"1580712207992\" \/><\/p>\n<p>\u70b9\u51fbapply\u7136\u540e\u70b9\u51fbOK<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712304894.png\" alt=\"1580712304894\" \/><\/p>\n<h5>\u30107.2\u3011\u767b\u5f55\u8fc7\u6ee4<\/h5>\n<p>\u8bbf\u95eehttp:\/\/localhost:8080\/platform\/home\u7684\u65f6\u5019\uff0c\u4f1a\u88ab<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712567791.png\" alt=\"1580712567791\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712593905.png\" alt=\"1580712593905\" \/><\/p>\n<h5>\u30107.3\u3011\u89d2\u8272\u8fc7\u6ee4<\/h5>\n<p>\u4f7f\u7528\u201cadmin\u201d\u7528\u6237\u767b\u5f55\uff0c\u5bc6\u7801\uff1a123<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713051410.png\" alt=\"1580713051410\" \/><\/p>\n<p>\u6839\u636eSecurityServiceImpl\u6211\u4eec\u53ef\u4ee5\u77e5\u9053\u4f7f\u7528admin\u8d26\u53f7<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580712777098.png\" alt=\"1580712777098\" \/><\/p>\n<p>\u767b\u5f55\u6210\u529f\u4e4b\u540e\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713214523.png\" alt=\"1580713214523\" \/><\/p>\n<p>\u6b64\u65f6\u70b9\u51fb\u201c\u5217\u8868\u201d\uff0c\u56e0\u4e3a\u5f53\u524dadmin\u7528\u6237\u662f\u6709admin\u89d2\u8272<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713320621.png\" alt=\"1580713320621\" \/><\/p>\n<p>\u6240\u6709\u53ef\u4ee5\u6b63\u5e38\u8bbf\u95ee<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713360368.png\" alt=\"1580713360368\" \/><\/p>\n<p>\u70b9\u51fb\u201c\u6dfb\u52a0\u201d\uff0c\u56e0\u4e3a\u5f53\u524dadmin\u7528\u6237\u662f\u6ca1\u6709order:add\u7684\u8d44\u6e90<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713455483.png\" alt=\"1580713455483\" \/><\/p>\n<p>\u6240\u4ee5\u56de401<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713488156.png\" alt=\"1580713488156\" \/><\/p>\n<h5>\u30107.4\u3011\u8d44\u6e90\u8fc7\u6ee4<\/h5>\n<p>\u70b9\u51fb\u201c\u9000\u51fa\u201d<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713654616.png\" alt=\"1580713654616\" \/><\/p>\n<p>\u4f7f\u7528\u201cjay\u201d\u7528\u6237\u767b\u5f55\uff0c\u5bc6\u7801\u4e3a123<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713770711.png\" alt=\"1580713770711\" \/><\/p>\n<p>\u70b9\u51fb\u201c\u6dfb\u52a0\u201d<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713818625.png\" alt=\"1580713818625\" \/><\/p>\n<p>\u56e0\u4e3aSecurityServiceImpl\u4e2d\u4e3ajay\u7528\u6237\u6dfb\u52a0\u5982\u4e0b\u7684\u8d44\u6e90<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713855307.png\" alt=\"1580713855307\" \/><\/p>\n<p>\u70b9\u51fb\u201c\u6dfb\u52a0\u201d\u4e4b\u540e\u6b63\u5e38\u8bbf\u95ee<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713814501.png\" alt=\"1580713814501\" \/><\/p>\n<p>\u70b9\u51fb\u201c\u5217\u8868\u201d\u4e4b\u540e\uff0c\u56e0\u4e3a\u201cjay\u201d\u7528\u6237\u6ee1\u610f\u201cadmin\u201d\u89d2\u8272\uff0c\u6240\u4ee5\u8bbf\u95ee\u53d7\u9650<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580713925370.png\" alt=\"1580713925370\" \/><\/p>\n<h3>4\u3001web\u9879\u76ee\u6388\u6743<\/h3>\n<p>\u524d\u9762\u6211\u4eec\u5b66\u4e60\u4e86\u57fa\u4e8eini\u6587\u4ef6\u914d\u7f6e\u65b9\u5f0f\u6765\u5b8c\u6210\u6388\u6743\uff0c\u4e0b\u9762\u6211\u4eec\u6765\u770b\u4e0b\u5176\u4ed62\u79cd\u65b9\u5f0f\u7684\u6388\u6743<\/p>\n<h4>\u30101\u3011\u57fa\u4e8e\u4ee3\u7801<\/h4>\n<h5>\u30101.1\u3011\u767b\u5f55\u76f8\u5173<\/h5>\n<table>\n<thead>\n<tr>\n<th>Subject \u767b\u5f55\u76f8\u5173\u65b9\u6cd5<\/th>\n<th>\u63cf\u8ff0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>isAuthenticated()<\/td>\n<td>\u8fd4\u56detrue \u8868\u793a\u5df2\u7ecf\u767b\u5f55\uff0c\u5426\u5219\u8fd4\u56defalse\u3002<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h5>\u30101.2\u3011\u89d2\u8272\u76f8\u5173<\/h5>\n<table>\n<thead>\n<tr>\n<th>Subject \u89d2\u8272\u76f8\u5173\u65b9\u6cd5<\/th>\n<th>\u63cf\u8ff0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>hasRole(String roleName)<\/td>\n<td>\u8fd4\u56detrue \u5982\u679cSubject \u88ab\u5206\u914d\u4e86\u6307\u5b9a\u7684\u89d2\u8272\uff0c\u5426\u5219\u8fd4\u56defalse\u3002<\/td>\n<\/tr>\n<tr>\n<td>hasRoles(List<String> roleNames)<\/td>\n<td>\u8fd4\u56detrue \u5982\u679cSubject \u88ab\u5206\u914d\u4e86\u6240\u6709\u6307\u5b9a\u7684\u89d2\u8272\uff0c\u5426\u5219\u8fd4\u56defalse\u3002<\/td>\n<\/tr>\n<tr>\n<td>hasAllRoles(Collection<String>roleNames)<\/td>\n<td>\u8fd4\u56de\u4e00\u4e2a\u4e0e\u65b9\u6cd5\u53c2\u6570\u4e2d\u76ee\u5f55\u4e00\u81f4\u7684hasRole \u7ed3\u679c\u7684\u96c6\u5408\u3002\u6709\u6027\u80fd\u7684\u63d0\u9ad8\u5982\u679c\u8bb8\u591a\u89d2\u8272\u9700\u8981\u6267\u884c\u68c0\u67e5\uff08\u4f8b\u5982\uff0c\u5f53\u81ea\u5b9a\u4e49\u4e00\u4e2a\u590d\u6742\u7684\u89c6\u56fe\uff09\u3002<\/td>\n<\/tr>\n<tr>\n<td>checkRole(String roleName)<\/td>\n<td>\u5b89\u9759\u5730\u8fd4\u56de\uff0c\u5982\u679cSubject \u88ab\u5206\u914d\u4e86\u6307\u5b9a\u7684\u89d2\u8272\uff0c\u4e0d\u7136\u7684\u8bdd\u5c31\u629b\u51faAuthorizationException\u3002<\/td>\n<\/tr>\n<tr>\n<td>checkRoles(Collection<String>roleNames)<\/td>\n<td>\u5b89\u9759\u5730\u8fd4\u56de\uff0c\u5982\u679cSubject \u88ab\u5206\u914d\u4e86\u6240\u6709\u7684\u6307\u5b9a\u7684\u89d2\u8272\uff0c\u4e0d\u7136\u7684\u8bdd\u5c31\u629b\u51faAuthorizationException\u3002<\/td>\n<\/tr>\n<tr>\n<td>checkRoles(String\u2026 roleNames)<\/td>\n<td>\u4e0e\u4e0a\u9762\u7684checkRoles \u65b9\u6cd5\u7684\u6548\u679c\u76f8\u540c\uff0c\u4f46\u5141\u8bb8Java5 \u7684var-args \u7c7b\u578b\u7684\u53c2\u6570<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h5>\u30101.3\u3011\u8d44\u6e90\u76f8\u5173<\/h5>\n<table>\n<thead>\n<tr>\n<th>Subject \u8d44\u6e90\u76f8\u5173\u65b9\u6cd5<\/th>\n<th>\u63cf\u8ff0<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>isPermitted(Permission p)<\/td>\n<td>\u8fd4\u56detrue \u5982\u679c\u8be5Subject \u88ab\u5141\u8bb8\u6267\u884c\u67d0\u52a8\u4f5c\u6216\u8bbf\u95ee\u88ab\u6743\u9650\u5b9e\u4f8b\u6307\u5b9a\u7684\u8d44\u6e90\uff0c\u5426\u5219\u8fd4\u56defalse<\/td>\n<\/tr>\n<tr>\n<td>isPermitted(List<Permission> perms)<\/td>\n<td>\u8fd4\u56de\u4e00\u4e2a\u4e0e\u65b9\u6cd5\u53c2\u6570\u4e2d\u76ee\u5f55\u4e00\u81f4\u7684isPermitted \u7ed3\u679c\u7684\u96c6\u5408\u3002<\/td>\n<\/tr>\n<tr>\n<td>isPermittedAll(Collection<Permission>perms)<\/td>\n<td>\u8fd4\u56detrue \u5982\u679c\u8be5Subject \u88ab\u5141\u8bb8\u6240\u6709\u6307\u5b9a\u7684\u6743\u9650\uff0c\u5426\u5219\u8fd4\u56defalse\u6709\u6027\u80fd\u7684\u63d0\u9ad8\u5982\u679c\u9700\u8981\u6267\u884c\u8bb8\u591a\u68c0\u67e5\uff08\u4f8b\u5982\uff0c\u5f53\u81ea\u5b9a\u4e49\u4e00\u4e2a\u590d\u6742\u7684\u89c6\u56fe\uff09<\/td>\n<\/tr>\n<tr>\n<td>isPermitted(String perm)<\/td>\n<td>\u8fd4\u56detrue \u5982\u679c\u8be5Subject \u88ab\u5141\u8bb8\u6267\u884c\u67d0\u52a8\u4f5c\u6216\u8bbf\u95ee\u88ab\u5b57\u7b26\u4e32\u6743\u9650\u6307\u5b9a\u7684\u8d44\u6e90\uff0c\u5426\u5219\u8fd4\u56defalse\u3002<\/td>\n<\/tr>\n<tr>\n<td>isPermitted(String\u2026perms)<\/td>\n<td>\u8fd4\u56de\u4e00\u4e2a\u4e0e\u65b9\u6cd5\u53c2\u6570\u4e2d\u76ee\u5f55\u4e00\u81f4\u7684isPermitted \u7ed3\u679c\u7684\u6570\u7ec4\u3002\u6709\u6027\u80fd\u7684\u63d0\u9ad8\u5982\u679c\u8bb8\u591a\u5b57\u7b26\u4e32\u6743\u9650\u68c0\u67e5\u9700\u8981\u88ab\u6267\u884c\uff08\u4f8b\u5982\uff0c\u5f53\u81ea\u5b9a\u4e49\u4e00\u4e2a\u590d\u6742\u7684\u89c6\u56fe\uff09\u3002<\/td>\n<\/tr>\n<tr>\n<td>isPermittedAll(String\u2026perms)<\/td>\n<td>\u8fd4\u56detrue \u5982\u679c\u8be5Subject \u88ab\u5141\u8bb8\u6240\u6709\u6307\u5b9a\u7684\u5b57\u7b26\u4e32\u6743\u9650\uff0c\u5426\u5219\u8fd4\u56defalse\u3002<\/td>\n<\/tr>\n<tr>\n<td>checkPermission(Permission p)<\/td>\n<td>\u5b89\u9759\u5730\u8fd4\u56de\uff0c\u5982\u679cSubject \u88ab\u5141\u8bb8\u6267\u884c\u67d0\u52a8\u4f5c\u6216\u8bbf\u95ee\u88ab\u7279\u5b9a\u7684\u6743\u9650\u5b9e\u4f8b\u6307\u5b9a\u7684\u8d44\u6e90\uff0c\u4e0d\u7136\u7684\u8bdd\u5c31\u629b\u51faAuthorizationException \u5f02\u5e38\u3002<\/td>\n<\/tr>\n<tr>\n<td>checkPermission(String perm)<\/td>\n<td>\u5b89\u9759\u5730\u8fd4\u56de\uff0c\u5982\u679cSubject \u88ab\u5141\u8bb8\u6267\u884c\u67d0\u52a8\u4f5c\u6216\u8bbf\u95ee\u88ab\u7279\u5b9a\u7684\u5b57\u7b26\u4e32\u6743\u9650\u6307\u5b9a\u7684\u8d44\u6e90\uff0c\u4e0d\u7136\u7684\u8bdd\u5c31\u629b\u51faAuthorizationException \u5f02\u5e38\u3002<\/td>\n<\/tr>\n<tr>\n<td>checkPermissions(Collection<Permission> perms)<\/td>\n<td>\u5b89\u9759\u5730\u8fd4\u56de\uff0c\u5982\u679cSubject \u88ab\u5141\u8bb8\u6240\u6709\u7684\u6743\u9650\uff0c\u4e0d\u7136\u7684\u8bdd\u5c31\u629b\u51faAuthorizationException \u5f02\u5e38\u3002\u6709\u6027\u80fd\u7684\u63d0\u9ad8\u5982\u679c\u9700\u8981\u6267\u884c\u8bb8\u591a\u68c0\u67e5\uff08\u4f8b\u5982\uff0c\u5f53\u81ea\u5b9a\u4e49\u4e00\u4e2a\u590d\u6742\u7684\u89c6\u56fe\uff09<\/td>\n<\/tr>\n<tr>\n<td>checkPermissions(String\u2026 perms)<\/td>\n<td>\u548c\u4e0a\u9762\u7684checkPermissions \u65b9\u6cd5\u6548\u679c\u76f8\u540c\uff0c\u4f46\u662f\u4f7f\u7528\u7684\u662f\u57fa\u4e8e\u5b57\u7b26\u4e32\u7684\u6743\u9650\u3002<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h5>\u30101.4\u3011\u6848\u4f8b<\/h5>\n<h6>\u30101.4.1\u3011\u521b\u5efa\u9879\u76ee<\/h6>\n<p>\u62f7\u8d1dshiro-day01-07web\u65b0\u5efashiro-day01-08web-java<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580799013486.png\" alt=\"1580799013486\" \/><\/p>\n<h6>\u30101.4.2\u3011\u4fee\u6539shiro.ini<\/h6>\n<pre><code class=\"language-ini line-numbers\">#\u58f0\u660e\u81ea\u5b9a\u4e49\u7684realm\uff0c\u4e14\u4e3a\u5b89\u5168\u7ba1\u7406\u5668\u6307\u5b9arealms\n[main]\ndefinitionRealm=com.itheima.shiro.realm.DefinitionRealm\nsecurityManager.realms=$definitionRealm\n#\u7528\u6237\u9000\u51fa\u540e\u8df3\u8f6c\u6307\u5b9aJSP\u9875\u9762\nlogout.redirectUrl=\/login.jsp\n#\u82e5\u6ca1\u6709\u767b\u5f55\uff0c\u5219\u88abauthc\u8fc7\u6ee4\u5668\u91cd\u5b9a\u5411\u5230login.jsp\u9875\u9762\nauthc.loginUrl = \/login.jsp\n[urls]\n\/login=anon\n#\u53d1\u9001\/home\u8bf7\u6c42\u9700\u8981\u5148\u767b\u5f55\n#\/home= authc\n#\u53d1\u9001\/order\/list\u8bf7\u6c42\u9700\u8981\u5148\u767b\u5f55\n#\/order-list = roles[admin]\n#\u63d0\u4ea4\u4ee3\u7801\u9700\u8981order:add\u6743\u9650\n#\/order-add = perms[\"order:add\"]\n#\u66f4\u65b0\u4ee3\u7801\u9700\u8981order:del\u6743\u9650\n#\/order-del = perms[\"order:del\"]\n#\u53d1\u9001\u9000\u51fa\u8bf7\u6c42\u5219\u7528\u9000\u51fa\u8fc7\u6ee4\u5668\n\/logout = logout\n\n<\/code><\/pre>\n<h6>\u30101.4.3\u3011\u767b\u5f55\u76f8\u5173<\/h6>\n<p>\u4fee\u6539HomeServlet\u7684doPost\u65b9\u6cd5<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.subject.Subject;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u7cfb\u7edfhome\u9875\u9762\n *\/\n@WebServlet(urlPatterns = \"\/home\")\npublic class HomeServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        \/\/\u901a\u8fc7subjectd\u5bf9\u8c61\u53bb\u5224\u65ad\u662f\u5426\u767b\u5f55\n        Subject subject = SecurityUtils.getSubject();\n        boolean flag  = subject.isAuthenticated();\n        if (flag){\n            resp.sendRedirect(\"home.jsp\");\n        }else {\n            req.getRequestDispatcher(\"\/login\").forward(req, resp);\n        }\n    }\n}\n\n\n<\/code><\/pre>\n<p>\u8bbf\u95eehttp:\/\/localhost:8080\/platform\/home   \u8fdb\u884cdebug<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580800060589.png\" alt=\"1580800060589\" \/><\/p>\n<p>\u6b64\u65f6\u6211\u4eec\u901a\u8fc7subject.isAuthenticated()\u5224\u65ad\u662f\u5426\u767b\u5f55\uff0c\u5982\u679c\u767b\u5f55\u5219\u91cd\u5b9a\u5411\u5230home.jsp,\u5982\u679c\u6ca1\u6709\u767b\u5f55\u5219\u8f6c\u53d1\u5230\/login\u5bf9\u5e94\u7684servlet<\/p>\n<h6>\u30101.4.4\u3011\u89d2\u8272\u76f8\u5173<\/h6>\n<p>\u4fee\u6539OrderListServlet\u7684doPost\u65b9\u6cd5\uff0c\u5224\u65ad\u662f\u5426\u6709admin\u89d2\u8272\uff0c\u5982\u679c\u6709\u5219\u8f6c\u53d1order-list.jsp,\u6ca1\u6709\u5219\u8f6c\u53d1\/login<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.subject.Subject;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u8ba2\u5355\u5217\u8868\n *\/\n@WebServlet(urlPatterns = \"\/order-list\")\npublic class OrderListServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        Subject subject = SecurityUtils.getSubject();\n        \/\/\u5224\u65ad\u5f53\u524d\u89d2\u8272\n        boolean flag = subject.hasRole(\"admin\");\n        if (flag){\n            req.getRequestDispatcher(\"order-list.jsp\").forward(req, resp);\n        }else {\n            req.getRequestDispatcher(\"\/login\").forward(req, resp);\n        }\n    }\n}\n\n<\/code><\/pre>\n<p>\u8bbf\u95eehttp:\/\/localhost:8080\/platform\/order-list<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580801658680.png\" alt=\"1580801658680\" \/><\/p>\n<p>\u56e0\u4e3a\u6b64\u65f6\u6211\u672a\u767b\u5f55\uff0c\u4e5f\u5c31\u662f\u8bf4\u5f53\u524d\u6ca1\u6709admin\u89d2\u8272\uff0c\u8fd9\u662f\u901a\u8fc7subject.hasRole(&#8220;admin&#8221;)\u8fd4\u56de\u672afalse<\/p>\n<h6>\u30101.4.5\u3011\u8d44\u6e90\u76f8\u5173<\/h6>\n<p>\u4fee\u6539OrderAddServlet<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.subject.Subject;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u6dfb\u52a0\u9875\u7801\n *\/\n@WebServlet(urlPatterns = \"\/order-add\")\npublic class OrderAddServlet extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        doPost(req, resp);\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp)\n            throws ServletException, IOException {\n        Subject subject = SecurityUtils.getSubject();\n        \/\/\u5224\u65ad\u662f\u5426\u6709\u5bf9\u5e94\u8d44\u6e90\n        boolean flag = subject.isPermitted(\"order:add\");\n        if (flag){\n            req.getRequestDispatcher(\"order-add.jsp\").forward(req, resp);\n        }else {\n            req.getRequestDispatcher(\"\/login\").forward(req, resp);\n        }\n    }\n\n}\n\n\n<\/code><\/pre>\n<p>\u8bbf\u95eehttp:\/\/localhost:8080\/platform\/order-add<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580802789329.png\" alt=\"1580802789329\" \/><\/p>\n<p>\u56e0\u4e3a\u6b64\u65f6\u6211\u672a\u767b\u5f55\uff0c\u4e5f\u5c31\u662f\u8bf4\u5f53\u524d\u6ca1\u6709order:add\u8d44\u6e90\uff0c\u901a\u8fc7 subject.isPermitted(&#8220;order:add&#8221;)\u8fd4\u56de\u672afalse<\/p>\n<h4>\u30102\u3011\u57fa\u4e8eJsp\u6807\u7b7e<\/h4>\n<h5>\u30102.1\u3011\u4f7f\u7528\u65b9\u5f0f<\/h5>\n<p>Shiro\u63d0\u4f9b\u4e86\u4e00\u5957JSP\u6807\u7b7e\u5e93\u6765\u5b9e\u73b0\u9875\u9762\u7ea7\u7684\u6388\u6743\u63a7\u5236\uff0c \u5728\u4f7f\u7528Shiro\u6807\u7b7e\u5e93\u524d\uff0c\u9996\u5148\u9700\u8981\u5728JSP\u5f15\u5165shiro\u6807\u7b7e\uff1a<\/p>\n<pre data-language=HTML><code class=\"language-markup line-numbers\">&lt;%@ taglib prefix=\"shiro\" uri=\"http:\/\/shiro.apache.org\/tags\" %&gt; \n\n\n<\/code><\/pre>\n<h5>\u30102.2\u3011\u76f8\u5173\u6807\u7b7e<\/h5>\n<table>\n<thead>\n<tr>\n<th>\u6807\u7b7e<\/th>\n<th>\u8bf4\u660e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>&lt; shiro:guest ><\/td>\n<td>\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u4e3a\u201c\u8bbf\u5ba2\u201d\uff0c\u5373\u672a\u8ba4\u8bc1\uff08\u5305\u542b\u672a\u8bb0\u4f4f\uff09\u7684\u7528\u6237<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:user ><\/td>\n<td>\u8ba4\u8bc1\u901a\u8fc7\u6216\u5df2\u8bb0\u4f4f\u7684\u7528\u6237<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:authenticated ><\/td>\n<td>\u5df2\u8ba4\u8bc1\u901a\u8fc7\u7684\u7528\u6237\u3002\u4e0d\u5305\u542b\u5df2\u8bb0\u4f4f\u7684\u7528\u6237\uff0c\u8fd9\u662f\u4e0euser\u6807\u7b7e\u7684\u533a\u522b\u6240\u5728<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:notAuthenticated ><\/td>\n<td>\u672a\u8ba4\u8bc1\u901a\u8fc7\u7528\u6237\u3002\u4e0eguest\u6807\u7b7e\u7684\u533a\u522b\u662f\uff0c\u8be5\u6807\u7b7e\u5305\u542b\u5df2\u8bb0\u4f4f\u7528\u6237<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:principal \/><\/td>\n<td>\u8f93\u51fa\u5f53\u524d\u7528\u6237\u4fe1\u606f\uff0c\u901a\u5e38\u4e3a\u767b\u5f55\u5e10\u53f7\u4fe1\u606f<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:hasRole name=&#8221;\u89d2\u8272&#8221;><\/td>\n<td>\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u5c5e\u4e8e\u8be5\u89d2\u8272<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:lacksRole name=&#8221;\u89d2\u8272&#8221;><\/td>\n<td>\u4e0ehasRole\u6807\u7b7e\u903b\u8f91\u76f8\u53cd\uff0c\u5f53\u7528\u6237\u4e0d\u5c5e\u4e8e\u8be5\u89d2\u8272\u65f6\u9a8c\u8bc1\u901a\u8fc7<\/td>\n<\/tr>\n<tr>\n<td>&lt; shiro:hasAnyRoles name=&#8221;a,b&#8221;><\/td>\n<td>\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u5c5e\u4e8e\u4ee5\u4e0b\u4efb\u610f\u4e00\u4e2a\u89d2\u8272<\/td>\n<\/tr>\n<tr>\n<td><shiro:hasPermission name=\u201c\u8d44\u6e90\u201d><\/td>\n<td>\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u62e5\u6709\u5236\u5b9a\u6743\u9650<\/td>\n<\/tr>\n<tr>\n<td><shiro:lacksPermission name=\"\u8d44\u6e90\"><\/td>\n<td>\u4e0epermission\u6807\u7b7e\u903b\u8f91\u76f8\u53cd\uff0c\u5f53\u524d\u7528\u6237\u6ca1\u6709\u5236\u5b9a\u6743\u9650\u65f6\uff0c\u9a8c\u8bc1\u901a\u8fc7<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h5>\u30102.3\u3011\u6848\u4f8b<\/h5>\n<h6>\u30102.3.1\u3011\u65b0\u5efa\u9879\u76ee<\/h6>\n<p>\u62f7\u8d1dshiro-day01-08web-java\u65b0\u5efashiro-day01-09web-jsp-taglib\u9879\u76ee<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580805725438.png\" alt=\"1580805725438\" \/><\/p>\n<h6>\u30102.3.2\u3011\u4fee\u6539home.jsp<\/h6>\n<pre data-language=HTML><code class=\"language-markup line-numbers\">&lt;%@ taglib prefix=\"c\" uri=\"http:\/\/java.sun.com\/jsp\/jstl\/core\" %&gt;\n&lt;%@ taglib prefix=\"shiro\" uri=\"http:\/\/shiro.apache.org\/tags\" %&gt;\n&lt;%@ page contentType=\"text\/html;charset=UTF-8\" language=\"java\" %&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;h6&gt;\n    &lt;a href=\"<span class=\"katex math inline\">{pageContext.request.contextPath}\/logout\"&gt;\u9000\u51fa&lt;\/a&gt;\n    &lt;shiro:hasRole name=\"admin\"&gt;\n    &lt;a href=\"<\/span>{pageContext.request.contextPath}\/order-list\"&gt;\u5217\u8868&lt;\/a&gt;\n    &lt;\/shiro:hasRole&gt;\n    &lt;shiro:hasPermission name=\"order:add\"&gt;\n    &lt;a href=\"${pageContext.request.contextPath}\/order-add\"&gt;\u6dfb\u52a0&lt;\/a&gt;\n    &lt;\/shiro:hasPermission&gt;\n&lt;\/h6&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n\n<\/code><\/pre>\n<p>\u30102.3.3\u3011\u6d4b\u8bd5<\/p>\n<p>\u8bbf\u95eehttp:\/\/localhost:8080\/platform\/login<\/p>\n<p>\u4f7f\u7528admin\/123\u767b\u5f55<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580806179855.png\" alt=\"1580806179855\" \/><\/p>\n<p>\u8fd9\u4e2a\u65f6\u5019\u6211\u4eec\u53ea\u80fd\u770b\u89c1\u201c\u5217\u8868\u201d\uff0c\u770b\u4e0d\u89c1\u201c\u6dfb\u52a0\u201d\uff0c\u70b9\u51fb\u201c\u9000\u51fa\u201d<\/p>\n<p>\u4f7f\u7528jay\/123\u767b\u5f55<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580806253525.png\" alt=\"1580806253525\" \/><\/p>\n<p>\u8fd9\u4e2a\u65f6\u5019\u6211\u4eec\u53ea\u80fd\u770b\u89c1\u201c\u6dfb\u52a0\u201d\uff0c\u770b\u4e0d\u89c1\u201c\u5217\u8868\u201d\uff0c\u70b9\u51fb\u201c\u9000\u51fa\u201d<\/p>\n<p>\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u8fd9\u91cc\u53ea\u662f\u9875\u9762\u662f\u5426\u663e\u793a\u5185\u5bb9\uff0c\u4e0d\u80fd\u9632\u6b62\u76d7\u94fe\u7684\u53d1\u751f<\/p>\n<h2>\u7b2c\u4e94\u7ae0 Springboot\u96c6\u6210Shiro<\/h2>\n<h3>1\u3001\u6280\u672f\u6808<\/h3>\n<p>\u4e3b\u6846\u67b6\uff1aspringboot<\/p>\n<p>\u54cd\u5e94\u5c42\uff1aspringMVC<\/p>\n<p>\u6301\u4e45\u5c42\uff1amybatis<\/p>\n<p>\u4e8b\u52a1\u63a7\u5236\uff1ajta<\/p>\n<p>\u524d\u7aef\u6280\u672f\uff1aeasyui<\/p>\n<h3>2\u3001\u6570\u636e\u5e93\u8bbe\u8ba1<\/h3>\n<h4>\u30101\u3011\u6570\u636e\u5e93\u56fe\u89e3<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580807847384.png\" alt=\"1580807847384\" \/><\/p>\n<p>sh_user:\u7528\u6237\u8868\uff0c\u4e00\u4e2a\u7528\u6237\u53ef\u4ee5\u6709\u591a\u4e2a\u89d2\u8272<\/p>\n<p>sh_role:\u89d2\u8272\u8868\uff0c\u4e00\u4e2a\u89d2\u8272\u53ef\u4ee5\u6709\u591a\u4e2a\u8d44\u6e90<\/p>\n<p>sh_resource:\u8d44\u6e90\u8868<\/p>\n<p>sh_user_role:\u7528\u6237\u89d2\u8272\u4e2d\u95f4\u8868<\/p>\n<p>sh_role_resource:\u89d2\u8272\u8d44\u6e90\u4e2d\u95f4\u8868<\/p>\n<h4>\u30102\u3011\u6570\u636e\u5e93\u811a\u672c<\/h4>\n<p>sh_user<\/p>\n<pre><code class=\"language-sql line-numbers\">CREATE TABLE `sh_user` (\n  `ID` varchar(36) NOT NULL COMMENT '\u4e3b\u952e',\n  `LOGIN_NAME` varchar(36) DEFAULT NULL COMMENT '\u767b\u5f55\u540d\u79f0',\n  `REAL_NAME` varchar(36) DEFAULT NULL COMMENT '\u771f\u5b9e\u59d3\u540d',\n  `NICK_NAME` varchar(36) DEFAULT NULL COMMENT '\u6635\u79f0',\n  `PASS_WORD` varchar(150) DEFAULT NULL COMMENT '\u5bc6\u7801',\n  `SALT` varchar(36) DEFAULT NULL COMMENT '\u52a0\u5bc6\u56e0\u5b50',\n  `SEX` int(11) DEFAULT NULL COMMENT '\u6027\u522b',\n  `ZIPCODE` varchar(36) DEFAULT NULL COMMENT '\u90ae\u7bb1',\n  `ADDRESS` varchar(36) DEFAULT NULL COMMENT '\u5730\u5740',\n  `TEL` varchar(36) DEFAULT NULL COMMENT '\u56fa\u5b9a\u7535\u8bdd',\n  `MOBIL` varchar(36) DEFAULT NULL COMMENT '\u7535\u8bdd',\n  `EMAIL` varchar(36) DEFAULT NULL COMMENT '\u90ae\u7bb1',\n  `DUTIES` varchar(36) DEFAULT NULL COMMENT '\u804c\u52a1',\n  `SORT_NO` int(11) DEFAULT NULL COMMENT '\u6392\u5e8f',\n  `ENABLE_FLAG` varchar(18) DEFAULT NULL COMMENT '\u662f\u5426\u6709\u6548',\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='\u7528\u6237\u8868';\n\n\n<\/code><\/pre>\n<p>sh_role<\/p>\n<pre><code class=\"language-sql line-numbers\">CREATE TABLE `sh_role` (\n  `ID` varchar(36) NOT NULL COMMENT '\u4e3b\u952e',\n  `ROLE_NAME` varchar(36) DEFAULT NULL COMMENT '\u89d2\u8272\u540d\u79f0',\n  `LABEL` varchar(36) DEFAULT NULL COMMENT '\u89d2\u8272\u6807\u8bc6',\n  `DESCRIPTION` varchar(200) DEFAULT NULL COMMENT '\u89d2\u8272\u63cf\u8ff0',\n  `SORT_NO` int(36) DEFAULT NULL COMMENT '\u6392\u5e8f',\n  `ENABLE_FLAG` varchar(18) DEFAULT NULL COMMENT '\u662f\u5426\u6709\u6548',\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='\u7528\u6237\u89d2\u8272\u8868';\n\n<\/code><\/pre>\n<p>sh_resource<\/p>\n<pre><code class=\"language-sql line-numbers\">CREATE TABLE `sh_resource` (\n  `ID` varchar(36) NOT NULL COMMENT '\u4e3b\u952e',\n  `PARENT_ID` varchar(36) DEFAULT NULL COMMENT '\u7236\u8d44\u6e90',\n  `RESOURCE_NAME` varchar(36) DEFAULT NULL COMMENT '\u8d44\u6e90\u540d\u79f0',\n  `REQUEST_PATH` varchar(200) DEFAULT NULL COMMENT '\u8d44\u6e90\u8def\u5f84',\n  `LABEL` varchar(200) DEFAULT NULL COMMENT '\u8d44\u6e90\u6807\u7b7e',\n  `ICON` varchar(20) DEFAULT NULL COMMENT '\u56fe\u6807',\n  `IS_LEAF` varchar(18) DEFAULT NULL COMMENT '\u662f\u5426\u53f6\u5b50\u8282\u70b9',\n  `RESOURCE_TYPE` varchar(36) DEFAULT NULL COMMENT '\u8d44\u6e90\u7c7b\u578b',\n  `SORT_NO` int(11) DEFAULT NULL COMMENT '\u6392\u5e8f',\n  `DESCRIPTION` varchar(200) DEFAULT NULL COMMENT '\u63cf\u8ff0',\n  `SYSTEM_CODE` varchar(36) DEFAULT NULL COMMENT '\u7cfb\u7edfcode',\n  `IS_SYSTEM_ROOT` varchar(18) DEFAULT NULL COMMENT '\u662f\u5426\u6839\u8282\u70b9',\n  `ENABLE_FLAG` varchar(18) DEFAULT NULL COMMENT '\u662f\u5426\u6709\u6548',\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='\u8d44\u6e90\u8868';\n\n\n<\/code><\/pre>\n<p>sh_role_resource<\/p>\n<pre><code class=\"language-sql line-numbers\">CREATE TABLE `sh_role_resource` (\n  `ID` varchar(36) NOT NULL,\n  `ENABLE_FLAG` varchar(18) DEFAULT NULL,\n  `ROLE_ID` varchar(36) DEFAULT NULL,\n  `RESOURCE_ID` varchar(36) DEFAULT NULL,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='\u89d2\u8272\u8d44\u6e90\u8868';\n\n<\/code><\/pre>\n<p>sh_user_role<\/p>\n<pre><code class=\"language-sql line-numbers\">CREATE TABLE `sh_user_role` (\n  `ID` varchar(36) NOT NULL,\n  `ENABLE_FLAG` varchar(18) DEFAULT NULL,\n  `USER_ID` varchar(36) DEFAULT NULL,\n  `ROLE_ID` varchar(36) DEFAULT NULL,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='\u7528\u6237\u89d2\u8272\u8868';\n\n<\/code><\/pre>\n<h3>3\u3001\u9879\u76ee\u9aa8\u67b6<\/h3>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581062691221.png\" alt=\"1581062691221\" \/><\/p>\n<h3>4\u3001ShiroDbRealm\u5b9a\u4e49<\/h3>\n<h4>\u30101\u3011\u56fe\u89e3<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1583895738811.png\" alt=\"1583895738811\" \/><\/p>\n<h4>\u30102\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p>\uff081\uff09\u3001ShiroDbRealmImpl\u7ee7\u627fShiroDbRealm\u5411\u4e0a\u7ee7\u627fAuthorizingRealm\uff0cShiroDbRealmImpl\u5b9e\u4f8b\u5316\u65f6\u4f1a\u521b\u5efa\u5bc6\u7801\u5339\u914d\u5668HashedCredentialsMatcher\u5b9e\u4f8b\uff0cHashedCredentialsMatcher\u6307\u5b9ahash\u6b21\u6570\u4e0e\u65b9\u5f0f\uff0c\u4ea4\u4e8eAuthenticatingRealm<\/p>\n<p>\uff082\uff09\u3001\u8c03\u7528login\u65b9\u6cd5\u540e\uff0c\u6700\u7ec8\u8c03\u7528doGetAuthenticationInfo(AuthenticationToken authcToken)\u65b9\u6cd5\uff0c\u62ff\u5230SimpleToken\u7684\u5bf9\u8c61\uff0c\u8c03\u7528UserBridgeService\u7684\u67e5\u627e\u7528\u6237\u65b9\u6cd5\uff0c\u628aShiroUser\u5bf9\u8c61\u3001\u5bc6\u7801\u548csalt\u4ea4\u4e8eSimpleAuthenticationInfo\u53bb\u8ba4\u8bc1<\/p>\n<p>\uff083\uff09\u3001\u8bbf\u95ee\u9700\u8981\u9274\u6743\u65f6\uff0c\u8c03\u7528doGetAuthorizationInfo(PrincipalCollection principals)\u65b9\u6cd5\uff0c\u7136\u540e\u8c03\u7528UserBridgeService\u7684\u6388\u6743\u9a8c\u8bc1<\/p>\n<h4>\u30103\u3011\u6838\u5fc3\u7c7b\u4ee3\u7801<\/h4>\n<h5>\u30103.1\u3011ShiroDbRealm<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core;\n\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.realm.AuthorizingRealm;\nimport org.apache.shiro.subject.PrincipalCollection;\n\nimport javax.annotation.PostConstruct;\n\n\n\/**\n *\n * @Description shiro\u81ea\u5b9a\u4e49realm\n *\/\npublic abstract class ShiroDbRealm extends AuthorizingRealm {\n\n    \/**\n     * @Description \u8ba4\u8bc1\n     * @param authcToken token\u5bf9\u8c61\n     * @return \n     *\/\n    public abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) ;\n\n    \/**\n     * @Description \u9274\u6743\n     * @param principals \u4ee4\u724c\n     * @return\n     *\/\n    public abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);\n\n    \/**\n     * @Description \u5bc6\u7801\u5339\u914d\u5668\n     *\/\n    @PostConstruct\n    public abstract void initCredentialsMatcher() ;\n\n\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.2\u3011ShiroDbRealmImpl<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.constant.SuperConstant;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleToken;\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.DigestsUtil;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.apache.shiro.util.ByteSource;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49shiro\u7684\u5b9e\u73b0\n *\/\npublic class ShiroDbRealmImpl extends ShiroDbRealm {\n\n    @Autowired\n    private UserBridgeService userBridgeService;\n\n\n    \/**\n     * @Description \u8ba4\u8bc1\u65b9\u6cd5\n     * @param authcToken \u6821\u9a8c\u4f20\u5165\u4ee4\u724c\n     * @return AuthenticationInfo\n     *\/\n    @Override\n    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {\n        SimpleToken token = (SimpleToken)authcToken;\n        User user  = userBridgeService.findUserByLoginName(token.getUsername());\n        if(EmptyUtil.isNullOrEmpty(user)){\n            throw new UnknownAccountException(\"\u8d26\u53f7\u4e0d\u5b58\u5728\");\n        }\n        ShiroUser shiroUser = BeanConv.toBean(user, ShiroUser.class);\n        shiroUser.setResourceIds(userBridgeService.findResourcesIdsList(user.getId()));\n        String salt = user.getSalt();\n        String password = user.getPassWord();\n        return new SimpleAuthenticationInfo(shiroUser, password, ByteSource.Util.bytes(salt), getName());\n    }\n\n    \/**\n     * @Description \u6388\u6743\u65b9\u6cd5\n     * @param principals SimpleAuthenticationInfo\u5bf9\u8c61\u7b2c\u4e00\u4e2a\u53c2\u6570\n     * @return\n     *\/\n    @Override\n    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();\n        return userBridgeService.getAuthorizationInfo(shiroUser);\n    }\n\n    \/**\n     * @Description \u52a0\u5bc6\u65b9\u5f0f\n     *\/\n    @Override\n    public void initCredentialsMatcher() {\n        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SuperConstant.HASH_ALGORITHM);\n        matcher.setHashIterations(SuperConstant.HASH_INTERATIONS);\n        setCredentialsMatcher(matcher);\n\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.3\u3011SimpleToken<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.base;\n\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\n\n\/**\n * @Description \u81ea\u5b9a\u4e49tooken\n *\/\npublic class SimpleToken extends UsernamePasswordToken {\n\n    \/** serialVersionUID *\/\n    private static final long serialVersionUID = -4849823851197352099L;\n\n    private String tokenType;\n\n    private String quickPassword;\n\n    \/**\n     * Constructor for SimpleToken\n     * @param tokenType\n     *\/\n    public SimpleToken(String tokenType, String username,String password) {\n        super(username,password);\n        this.tokenType = tokenType;\n    }\n\n    public SimpleToken(String tokenType, String username,String password,String quickPassword) {\n        super(username,password);\n        this.tokenType = tokenType;\n        this.quickPassword = quickPassword;\n    }\n\n    public String getTokenType() {\n        return tokenType;\n    }\n\n    public void setTokenType(String tokenType) {\n        this.tokenType = tokenType;\n    }\n\n    public String getQuickPassword() {\n        return quickPassword;\n    }\n\n    public void setQuickPassword(String quickPassword) {\n        this.quickPassword = quickPassword;\n    }\n\n\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.4\u3011ShiroUser<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.base;\n\nimport com.itheima.shiro.utils.ToString;\nimport lombok.Data;\n\nimport java.util.List;\n\n\n\/**\n * @Description \u81ea\u5b9a\u4e49Authentication\u5bf9\u8c61\uff0c\u4f7f\u5f97Subject\u9664\u4e86\u643a\u5e26\u7528\u6237\u7684\u767b\u5f55\u540d\u5916\u8fd8\u53ef\u4ee5\u643a\u5e26\u66f4\u591a\u4fe1\u606f\n *\/\n@Data\npublic class  ShiroUser extends ToString {\n\n    \/** serialVersionUID *\/\n    private static final long serialVersionUID = -5024855628064590607L;\n\n    \/**\n     * \u4e3b\u952e\n     *\/\n    private String id;\n\n    \/**\n     * \u767b\u5f55\u540d\u79f0\n     *\/\n    private String loginName;\n\n    \/**\n     * \u771f\u5b9e\u59d3\u540d\n     *\/\n    private String realName;\n\n    \/**\n     * \u6635\u79f0\n     *\/\n    private String nickName;\n\n    \/**\n     * \u5bc6\u7801\n     *\/\n    private String passWord;\n\n    \/**\n     * \u52a0\u5bc6\u56e0\u5b50\n     *\/\n    private String salt;\n\n    \/**\n     * \u6027\u522b\n     *\/\n    private Integer sex;\n\n    \/**\n     * \u90ae\u7bb1\n     *\/\n    private String zipcode;\n\n    \/**\n     * \u5730\u5740\n     *\/\n    private String address;\n\n    \/**\n     * \u56fa\u5b9a\u7535\u8bdd\n     *\/\n    private String tel;\n\n    \/**\n     * \u7535\u8bdd\n     *\/\n    private String mobil;\n\n    \/**\n     * \u90ae\u7bb1\n     *\/\n    private String email;\n\n    \/**\n     * \u804c\u52a1\n     *\/\n    private String duties;\n\n    \/**\n     * \u6392\u5e8f\n     *\/\n    private Integer sortNo;\n\n    \/**\n     * \u662f\u5426\u6709\u6548\n     *\/\n    private String enableFlag;\n\n    private List&lt;String&gt; resourceIds;\n\n    public ShiroUser() {\n        super();\n    }\n\n    public ShiroUser(String id, String loginName) {\n        super();\n        this.id = id;\n        this.loginName = loginName;\n    }\n\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((email == null) ? 0 : email.hashCode());\n        result = prime * result + ((id == null) ? 0 : id.hashCode());\n        result = prime * result\n                + ((loginName == null) ? 0 : loginName.hashCode());\n        result = prime * result + ((mobil == null) ? 0 : mobil.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        ShiroUser other = (ShiroUser) obj;\n        if (email == null) {\n            if (other.email != null)\n                return false;\n        } else if (!email.equals(other.email))\n            return false;\n        if (id == null) {\n            if (other.id != null)\n                return false;\n        } else if (!id.equals(other.id))\n            return false;\n        if (loginName == null) {\n            if (other.loginName != null)\n                return false;\n        } else if (!loginName.equals(other.loginName))\n            return false;\n        if (mobil == null) {\n            if (other.mobil != null)\n                return false;\n        } else if (!mobil.equals(other.mobil))\n            return false;\n        return true;\n    }\n\n\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.5\u3011UserBridgeService<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.bridge;\n\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.pojo.User;\nimport org.apache.shiro.authz.AuthorizationInfo;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7528\u6237\u4fe1\u606f\u6865\u63a5\uff08\u540e\u671f\u4f1a\u505a\u7f13\u5b58\uff09\n *\/\npublic interface UserBridgeService {\n\n\n    \/**\n     * @Description \u67e5\u627e\u7528\u6237\u4fe1\u606f\n     * @param loginName \u7528\u6237\u540d\u79f0\n     * @return user\u5bf9\u8c61\n     *\/\n    User findUserByLoginName(String loginName);\n\n    \/**\n     * @Description \u9274\u6743\u65b9\u6cd5\n     * @param shiroUser \u4ee4\u724c\u5bf9\u8c61\n     * @return \u9274\u6743\u4fe1\u606f\n     *\/\n    AuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser);\n\n    \/**\n     * @Description \u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u89d2\u8272\u6807\u8bc6list\n     * @param userId \u7528\u6237id\n     * @return \u89d2\u8272\u6807\u8bc6\u96c6\u5408\n     *\/\n    List&lt;String&gt; findRoleList(String userId);\n\n    \/**\n     * @Description \u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u8d44\u6e90\u6807\u8bc6list\n     * @param userId \u7528\u6237id\n     * @return \u8d44\u6e90\u6807\u8bc6\u96c6\u5408\n     *\/\n    List&lt;String&gt; findResourcesList(String userId);\n\n    \/**\n     * @Description \u67e5\u8be2\u8d44\u6e90ids\n     * @param userId \u7528\u6237id\n     * @return \u8d44\u6e90id\u96c6\u5408\n     *\/\n    List&lt;String&gt; findResourcesIds(String userId);\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.6\u3011UserBridgeServiceImpl<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.bridge.impl;\n\nimport com.itheima.shiro.core.adapter.UserAdapter;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.pojo.Resource;\nimport com.itheima.shiro.pojo.Role;\nimport com.itheima.shiro.pojo.User;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7528\u6237\u4fe1\u606f\u6865\u63a5\uff08\u540e\u671f\u4f1a\u505a\u7f13\u5b58\uff09\n *\/\n@Component(\"userBridgeService\")\npublic class UserBridgeServiceImpl implements UserBridgeService {\n\n    @Autowired\n    UserAdapter userAdapter;\n\n    @Override\n    public User findUserByLoginName(String loginName) {\n\n        return userAdapter.findUserByLoginName(loginName);\n    }\n\n    @Override\n    public AuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser) {\n        \/\/\u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u7684\u89d2\u8272\u6807\u8bc6\n        List&lt;String&gt; roleList = this.findRoleList(shiroUser.getId());\n        \/\/\u67e5\u8be2\u7528\u6237\u5bf9\u4e8e\u7684\u8d44\u6e90\u6807\u8bc6\n        List&lt;String&gt; resourcesList = this.findResourcesList(shiroUser.getId());\n        \/\/\u6784\u5efa\u9274\u6743\u4fe1\u606f\u5bf9\u8c61\n        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();\n        simpleAuthorizationInfo.addRoles(roleList);\n        simpleAuthorizationInfo.addStringPermissions(resourcesList);\n        return simpleAuthorizationInfo;\n    }\n\n    @Override\n    public List&lt;String&gt; findRoleList(String userId){\n        List&lt;Role&gt; roles = userAdapter.findRoleByUserId(userId);\n        List&lt;String&gt; roleLabel = new ArrayList&lt;&gt;();\n        for (Role role : roles) {\n            roleLabel.add(role.getLabel());\n        }\n        return roleLabel;\n    }\n\n    @Override\n    public List&lt;String&gt; findResourcesList(String userId){\n        List&lt;Resource&gt; resources = userAdapter.findResourceByUserId(userId);\n        List&lt;String&gt; resourceLabel = new ArrayList&lt;&gt;();\n        for (Resource resource : resources) {\n            resourceLabel.add(resource.getLabel());\n        }\n        return resourceLabel;\n    }\n\n    @Override\n    public List&lt;String&gt; findResourcesIds(String userId) {\n        List&lt;Resource&gt; resources = userAdapter.findResourceByUserId(userId);\n        List&lt;String&gt; ids = new ArrayList&lt;&gt;();\n        for (Resource resource : resources) {\n            ids.add(resource.getId());\n        }\n        return ids;\n    }\n\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.7\u3011UserAdapter<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.adapter;\n\nimport com.itheima.shiro.pojo.Resource;\nimport com.itheima.shiro.pojo.Role;\nimport com.itheima.shiro.pojo.User;\n\nimport java.util.List;\n\n\n\/**\n * @Description \u540e\u53f0\u767b\u9646\u7528\u6237\u9002\u914d\u5668\u63a5\u53e3\n *\/\n\npublic interface UserAdapter {\n\n    \/**\n     * @Description \u6309\u7528\u6237\u540d\u67e5\u627e\u7528\u6237\n     * @param loginName \u767b\u5f55\u540d\n     * @return\n     *\/\n    User findUserByLoginName(String loginName);\n\n    \/**\n     * @Description \u67e5\u627e\u7528\u6237\u6240\u6709\u89d2\u8272\n     * @param userId \u7528\u6237Id\n     * @return\n     *\/\n    List&lt;Role&gt; findRoleByUserId(String userId);\n\n    \/**\n     * @Description \u67e5\u8be2\u7528\u6237\u6709\u90a3\u4e9b\u8d44\u6e90\n     * @param userId \u7528\u6237Id\n     * @return\n     *\/\n    List&lt;Resource&gt; findResourceByUserId(String userId);\n\n}\n\n\n<\/code><\/pre>\n<h5>\u30103.8\u3011UserAdapterImpl<\/h5>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.adapter.impl;\n\nimport com.itheima.shiro.constant.SuperConstant;\nimport com.itheima.shiro.core.adapter.UserAdapter;\nimport com.itheima.shiro.mapper.UserMapper;\nimport com.itheima.shiro.mappercustom.UserAdapterMapper;\nimport com.itheima.shiro.pojo.Resource;\nimport com.itheima.shiro.pojo.Role;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.pojo.UserExample;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n\n\/**\n * @Description \u540e\u53f0\u767b\u9646\u7528\u6237\u9002\u914d\u5668\u63a5\u53e3\u5b9e\u73b0\n *\/\n@Component(\"userAdapter\")\npublic class UserAdapterImpl implements UserAdapter {\n\n    @Autowired\n    private UserMapper userMapper;\n\n    @Autowired\n    private UserAdapterMapper userAdapterMapper;\n\n    @Override\n    public User findUserByLoginName(String loginName) {\n        UserExample userExample = new UserExample();\n        userExample.createCriteria().andEnableFlagEqualTo(SuperConstant.YES).andLoginNameEqualTo(loginName);\n        List&lt;User&gt; userList = userMapper.selectByExample(userExample);\n        if (userList.size()==1) {\n            return userList.get(0);\n        }else {\n            return null;\n        }\n    }\n\n    @Override\n    public List&lt;Role&gt; findRoleByUserId(String userId) {\n        Map&lt;String, Object&gt; values = new HashMap&lt;String, Object&gt;();\n        values.put(\"userId\", userId);\n        values.put(\"enableFlag\", SuperConstant.YES);\n        List&lt;Role&gt; list = userAdapterMapper.findRoleByUserId(values);\n        return list;\n    }\n\n    @Override\n    public List&lt;Resource&gt; findResourceByUserId(String userId) {\n        Map&lt;String, Object&gt; values = new HashMap&lt;String, Object&gt;();\n        values.put(\"userId\", userId);\n        values.put(\"enableFlag\", SuperConstant.YES);\n        List&lt;Resource&gt; list=userAdapterMapper.findResourceByUserId(values);\n        return list;\n    }\n}\n\n\n<\/code><\/pre>\n<h3>5\u3001ShiroConfig\u914d\u7f6e<\/h3>\n<h4>\u30101\u3011\u56fe\u89e3<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581064915787.png\" alt=\"1581064915787\" \/><\/p>\n<h4>\u30102\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p>\uff081\uff09\u3001\u521b\u5efaSimpleCookie\uff0c\u8bbf\u95ee\u9879\u76ee\u65f6\uff0c\u4f1a\u5728\u5ba2\u6237\u7aef\u4e2dcookie\u4e2d\u5b58\u653eShiroSession\u7684\u5bf9<\/p>\n<p>\uff082\uff09\u3001\u521b\u5efaDefaultWebSessionManager\u4f1a\u8bdd\u7ba1\u7406\u5668\u5b9a\u4e49cookie\u673a\u5236\u3001\u5b9a\u65f6\u5237\u65b0\u3001\u5168\u5c40\u4f1a\u8bdd\u8d85\u65f6\u65f6\u95f4\u7136\u540e\u4ea4<\/p>\n<p>\u4e8eDefaultWebSecurityManager\u6743\u9650\u7ba1\u7406\u5668\u7ba1\u7406<\/p>\n<p>\uff083\uff09\u3001\u521b\u5efa\u81ea\u5b9a\u4e49ShiroDbRealm\u5b9e\u73b0\uff0c\u7528\u4e8e\u6743\u9650\u8ba4\u8bc1\u3001\u6388\u6743\u3001\u52a0\u5bc6\u65b9\u5f0f\u7684\u7ba1\u7406\uff0c\u540c\u65f6\u4ece\u6570\u636e\u5e93\u4e2d\u53d6\u5f97\u76f8\u5173\u7684<\/p>\n<p>\u89d2\u8272\u3001\u8d44\u6e90\u3001\u7528\u6237\u7684\u4fe1\u606f\uff0c\u7136\u540e\u4ea4\u4e8eDefaultWebSecurityManager\u6743\u9650\u7ba1\u7406\u5668\u7ba1\u7406<\/p>\n<p>\uff084\uff09\u3001\u521b\u5efaDefaultWebSecurityManager\u6743\u9650\u7ba1\u7406\u5668\u7528\u4e8e\u7ba1\u7406DefaultWebSessionManager\u4f1a\u8bdd\u7ba1\u7406\u5668\u3001ShiroDbRealm<\/p>\n<p>\uff085\uff09\u3001\u521b\u5efalifecycleBeanPostProcessor\u548cDefaultAdvisorAutoProxyCreator\u76f8\u4e92\u914d\u5408\u4e8b\u9879\u6ce8\u89e3\u7684\u6743\u9650\u9274\u6743<\/p>\n<p>\uff086\uff09\u3001\u521b\u5efaShiroFilterFactoryBean\u7684shiro\u8fc7\u6ee4\u5668\u6307\u5b9a\u6743\u9650\u7ba1\u7406\u5668\u3001\u540c\u65f6\u542f\u52a8\u8fde\u63a5\u94fe\u53ca\u767b\u5f55URL\u3001\u672a\u767b\u5f55\u7684URL<\/p>\n<p>\u7684\u8df3\u8f6c<\/p>\n<h4>\u30103\u3011ShiroConfig\u4ee3\u7801<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\n\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.impl.ShiroDbRealmImpl;\nimport com.itheima.shiro.properties.PropertiesUtil;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u6743\u9650\u914d\u7f6e\u7c7b\n *\/\n@Configuration\n@ComponentScan(basePackages = \"com.itheima.shiro.core\")\n@Log4j2\npublic class ShiroConfig {\n\n    \/**\n     * @Description \u521b\u5efacookie\u5bf9\u8c61\n     *\/\n    @Bean(name=\"sessionIdCookie\")\n    public SimpleCookie simpleCookie(){\n        SimpleCookie simpleCookie = new SimpleCookie();\n        simpleCookie.setName(\"ShiroSession\");\n        return simpleCookie;\n    }\n\n    \/**\n     * @Description \u6743\u9650\u7ba1\u7406\u5668\n     *\/\n    @Bean(name=\"securityManager\")\n    public DefaultWebSecurityManager defaultWebSecurityManager(){\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(shiroDbRealm());\n        securityManager.setSessionManager(shiroSessionManager());\n        return securityManager;\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49RealmImpl\n     *\/\n    @Bean(name=\"shiroDbRealm\")\n    public ShiroDbRealm shiroDbRealm(){\n        return new ShiroDbRealmImpl();\n    }\n\n\n    \/**\n     * @Description \u4f1a\u8bdd\u7ba1\u7406\u5668\n     *\/\n    @Bean(name=\"sessionManager\")\n    public DefaultWebSessionManager shiroSessionManager(){\n        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();\n        sessionManager.setSessionValidationSchedulerEnabled(false);\n        sessionManager.setSessionIdCookieEnabled(true);\n        sessionManager.setSessionIdCookie(simpleCookie());\n        sessionManager.setGlobalSessionTimeout(3600000);\n        return sessionManager;\n    }\n\n    \/**\n     * @Description \u4fdd\u8bc1\u5b9e\u73b0\u4e86Shiro\u5185\u90e8lifecycle\u51fd\u6570\u7684bean\u6267\u884c\n     *\/\n    @Bean(name = \"lifecycleBeanPostProcessor\")\n    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    \/**\n     * @Description AOP\u5f0f\u65b9\u6cd5\u7ea7\u6743\u9650\u68c0\u67e5\n     *\/\n    @Bean\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);\n        return defaultAdvisorAutoProxyCreator;\n    }\n\n    \/**\n     * @Description \u914d\u5408DefaultAdvisorAutoProxyCreator\u4e8b\u9879\u6ce8\u89e3\u6743\u9650\u6821\u9a8c\n     *\/\n    @Bean\n    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {\n        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();\n        aasa.setSecurityManager(defaultWebSecurityManager());\n        return new AuthorizationAttributeSourceAdvisor();\n    }\n\n    \/**\n     * @Description \u8fc7\u6ee4\u5668\u94fe\n     *\/\n    private Map&lt;String, String&gt; filterChainDefinition(){\n        List&lt;Object&gt; list  = PropertiesUtil.propertiesShiro.getKeyList();\n        Map&lt;String, String&gt; map = new LinkedHashMap&lt;&gt;();\n        for (Object object : list) {\n            String key = object.toString();\n            String value = PropertiesUtil.getShiroValue(key);\n            log.info(\"\u8bfb\u53d6\u9632\u6b62\u76d7\u94fe\u63a7\u5236\uff1a---key{},---value:{}\",key,value);\n            map.put(key, value);\n        }\n        return map;\n    }\n\n    \/**\n     * @Description Shiro\u8fc7\u6ee4\u5668\n     *\/\n    @Bean(\"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilterFactoryBean(){\n        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(defaultWebSecurityManager());\n        shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());\n        shiroFilter.setLoginUrl(\"\/login\");\n        shiroFilter.setUnauthorizedUrl(\"\/login\");\n        return shiroFilter;\n    }\n\n}\n\n\n<\/code><\/pre>\n<h3>6\u3001Shiro\u8fc7\u6ee4\u5668\u3001\u8fc7\u6ee4\u5668\u94fe<\/h3>\n<h4>\u30101\u3011\u8fc7\u6ee4\u5668<\/h4>\n<p>Shiro\u5185\u7f6e\u4e86\u5f88\u591a\u9ed8\u8ba4\u7684\u8fc7\u6ee4\u5668\uff0c\u6bd4\u5982\u8eab\u4efd\u9a8c\u8bc1\u3001\u6388\u6743\u7b49\u76f8\u5173\u7684\u3002\u9ed8\u8ba4\u8fc7\u6ee4\u5668\u53ef\u4ee5\u53c2\u8003org.apache.shiro.web.filter.mgt.DefaultFilter\u4e2d\u7684\u679a\u4e3e\u8fc7\u6ee4\u5668<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1580542509773.png\" alt=\"1580542509773\" \/><\/p>\n<h4>\u30102\u3011\u8fc7\u6ee4\u5668\u94fe<\/h4>\n<p>\u5b9a\u4e49\uff1aauthentication.properties<\/p>\n<pre><code class=\"language-properties line-numbers\">#\u9759\u6001\u8d44\u6e90\u4e0d\u8fc7\u6ee4\n\/static\/**=anon\n#\u767b\u5f55\u94fe\u63a5\u4e0d\u8fc7\u6ee4\n\/login\/**=anon\n#\u5176\u4ed6\u94fe\u63a5\u662f\u9700\u8981\u767b\u5f55\u7684\n\/**=authc\n\n<\/code><\/pre>\n<p>\u6ce8\u610f\uff1a\u8fd9\u91cc\u5b9a\u4e49\u7684\u8fc7\u6ee4\u5668\u662f\u6709\u6267\u884c\u987a\u5e8f\u7684\uff0c\u4ece\u4e0a\u5411\u4e0b\u6267\u884c<\/p>\n<h4>\u30103\u3011\u52a0\u8f7d\u539f\u7406\u5206\u6790<\/h4>\n<p>\u5b9a\u4e49\uff1aPropertiesUtil\uff0c\u4ececlasspath\u4e2d\u52a0\u8f7dauthentication.properties<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.properties;\n\nimport com.itheima.shiro.utils.EmptyUtil;\nimport lombok.extern.log4j.Log4j2;\n\n\/**\n * @Description \u8bfb\u53d6Properties\u7684\u5de5\u5177\u7c7b\n *\/\n@Log4j2\npublic class PropertiesUtil {\n\n    public static LinkProperties propertiesShiro = new LinkProperties();\n\n    \/**\n     * \u8bfb\u53d6properties\u914d\u7f6e\u6587\u4ef6\u4fe1\u606f\n     *\/\n    static {\n        String sysName = System.getProperty(\"sys.name\");\n        if (EmptyUtil.isNullOrEmpty(sysName)) {\n            sysName = \"application.properties\";\n        } else {\n            sysName += \".properties\";\n        }\n        try {\n            propertiesShiro.load(PropertiesUtil.class.getClassLoader()\n                    .getResourceAsStream(\"authentication.properties\"));\n        } catch (Exception e) {\n            log.warn(\"\u8d44\u6e90\u8def\u5f84\u4e2d\u4e0d\u5b58\u5728authentication.properties\u6743\u9650\u6587\u4ef6\uff0c\u5ffd\u7565\u8bfb\u53d6\uff01\");\n        }\n    }\n\n    \/**\n     * \u6839\u636ekey\u5f97\u5230value\u7684\u503c\n     *\/\n    public static String getShiroValue(String key) {\n        return propertiesShiro.getProperty(key);\n    }\n\n}\n\n\n<\/code><\/pre>\n<p>\u5b9a\u4e49LinkProperties\uff0c\u8fd9\u4e2a\u7c7b\u4fdd\u8bc1\u4e86Properties\u7c7b\u7684\u6709\u5e8f<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.properties;\n\nimport java.io.*;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Properties;\n\n\n\/**\n * @Description \u6709\u5e8fProperties\u7c7b\n *\/\n\npublic class LinkProperties extends Properties{\n\n    \/** serialVersionUID *\/\n    private static final long serialVersionUID = 7573016303908223266L;\n\n    private List&lt;Object&gt; keyList = new ArrayList&lt;Object&gt;();  \n\n    \/** \n     * \u9ed8\u8ba4\u6784\u9020\u65b9\u6cd5 \n     *\/  \n    public LinkProperties() {  \n\n    }  \n\n    \/** \n     * \u4ece\u6307\u5b9a\u8def\u5f84\u52a0\u8f7d\u4fe1\u606f\u5230Properties \n     * @param path \n     *\/  \n    public LinkProperties(String path) {  \n        try {  \n            InputStream is = new FileInputStream(path);  \n            this.load(is);  \n        } catch (FileNotFoundException e) {  \n            e.printStackTrace();  \n            throw new RuntimeException(\"\u6307\u5b9a\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\");  \n        } catch (IOException e) {  \n            e.printStackTrace();  \n        }  \n    }  \n\n    \/** \n     * \u91cd\u5199put\u65b9\u6cd5\uff0c\u6309\u7167property\u7684\u5b58\u5165\u987a\u5e8f\u4fdd\u5b58key\u5230keyList\uff0c\u9047\u5230\u91cd\u590d\u7684\u540e\u8005\u5c06\u8986\u76d6\u524d\u8005\u3002 \n     *\/  \n    @Override  \n    public synchronized Object put(Object key, Object value) {  \n        this.removeKeyIfExists(key);  \n        keyList.add(key);  \n        return super.put(key, value);  \n    }  \n\n\n    \/** \n     * \u91cd\u5199remove\u65b9\u6cd5\uff0c\u5220\u9664\u5c5e\u6027\u65f6\u6e05\u9664keyList\u4e2d\u5bf9\u5e94\u7684key\u3002 \n     *\/  \n    @Override  \n    public synchronized Object remove(Object key) {  \n        this.removeKeyIfExists(key);  \n        return super.remove(key);  \n    }  \n\n    \/** \n     * keyList\u4e2d\u5b58\u5728\u6307\u5b9a\u7684key\u65f6\u5219\u5c06\u5176\u5220\u9664 \n     *\/  \n    private void removeKeyIfExists(Object key) {  \n        keyList.remove(key);  \n    }  \n\n    \/** \n     * \u83b7\u53d6Properties\u4e2dkey\u7684\u6709\u5e8f\u96c6\u5408 \n     * @return \n     *\/  \n    public List&lt;Object&gt; getKeyList() {  \n        return keyList;  \n    }  \n\n    \/** \n     * \u4fdd\u5b58Properties\u5230\u6307\u5b9a\u6587\u4ef6\uff0c\u9ed8\u8ba4\u4f7f\u7528UTF-8\u7f16\u7801 \n     * @param path \u6307\u5b9a\u6587\u4ef6\u8def\u5f84 \n     *\/  \n    public void store(String path) {  \n        this.store(path, \"UTF-8\");  \n    }  \n\n    \/** \n     * \u4fdd\u5b58Properties\u5230\u6307\u5b9a\u6587\u4ef6\uff0c\u5e76\u6307\u5b9a\u5bf9\u5e94\u5b58\u653e\u7f16\u7801 \n     * @param path \u6307\u5b9a\u8def\u5f84 \n     * @param charset \u6587\u4ef6\u7f16\u7801 \n     *\/  \n    public void store(String path, String charset) {  \n        if (path != null &amp;&amp; !\"\".equals(path)) {  \n            try {  \n                OutputStream os = new FileOutputStream(path);  \n                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, charset));  \n                this.store(bw, null);  \n                bw.close();  \n            } catch (FileNotFoundException e) {  \n                e.printStackTrace();  \n            } catch (IOException e) {  \n                e.printStackTrace();  \n            }  \n        } else {  \n            throw new RuntimeException(\"\u5b58\u50a8\u8def\u5f84\u4e0d\u80fd\u4e3a\u7a7a!\");  \n        }  \n    }  \n\n    \/** \n     * \u91cd\u5199keys\u65b9\u6cd5\uff0c\u8fd4\u56de\u6839\u636ekeyList\u9002\u914d\u7684Enumeration\uff0c\u4e14\u4fdd\u6301HashTable keys()\u65b9\u6cd5\u7684\u539f\u6709\u8bed\u4e49\uff0c \n     * \u6bcf\u6b21\u90fd\u8c03\u7528\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684Enumeration\u5bf9\u8c61\uff0c\u4e14\u548c\u4e4b\u524d\u7684\u4e0d\u4ea7\u751f\u51b2\u7a81 \n     *\/  \n    @Override  \n    public synchronized Enumeration&lt;Object&gt; keys() {  \n        return new EnumerationAdapter&lt;Object&gt;(keyList);  \n    }  \n\n    \/** \n     * List\u5230Enumeration\u7684\u9002\u914d\u5668 \n     *\/  \n    private class EnumerationAdapter&lt;T&gt; implements Enumeration&lt;T&gt; {  \n        private int index = 0;  \n        private final List&lt;T&gt; list;  \n        private final boolean isEmpty;  \n\n        public EnumerationAdapter(List&lt;T&gt; list) {  \n            this.list = list;  \n            this.isEmpty = list.isEmpty();  \n        }  \n\n        public boolean hasMoreElements() {  \n            \/\/isEmpty\u7684\u5f15\u5165\u662f\u4e3a\u4e86\u66f4\u8d34\u8fd1HashTable\u539f\u6709\u7684\u8bed\u4e49\uff0c\u5728HashTable\u4e2d\u6dfb\u52a0\u5143\u7d20\u524d\u8c03\u7528\u5176keys()\u65b9\u6cd5\u83b7\u5f97\u4e00\u4e2aEnumeration\u7684\u5f15\u7528\uff0c  \n            \/\/\u4e4b\u540e\u5f80HashTable\u4e2d\u6dfb\u52a0\u6570\u636e\u540e\uff0c\u8c03\u7528\u4e4b\u524d\u83b7\u53d6\u5230\u7684Enumeration\u7684hasMoreElements()\u5c06\u8fd4\u56defalse\uff0c\u4f46\u5982\u679c\u6b64\u65f6\u91cd\u65b0\u83b7\u53d6\u4e00\u4e2a  \n            \/\/Enumeration\u7684\u5f15\u7528\uff0c\u5219\u65b0Enumeration\u7684hasMoreElements()\u5c06\u8fd4\u56detrue\uff0c\u800c\u4e14\u4e4b\u540e\u5bf9HashTable\u6570\u636e\u7684\u589e\u3001\u5220\u3001\u6539\u90fd\u662f\u53ef\u4ee5\u5728  \n            \/\/nextElement\u4e2d\u83b7\u53d6\u5230\u7684\u3002  \n            return !isEmpty &amp;&amp; index &lt; list.size();  \n        }  \n\n        public T nextElement() {  \n            if (this.hasMoreElements()) {  \n                return list.get(index++);  \n            }  \n            return null;  \n        }  \n\n    }  \n}\n\n\n<\/code><\/pre>\n<p>\u67e5\u770bshirocConfig<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581078295529.png\" alt=\"1581078295529\" \/><\/p>\n<p>\u52a0\u8f7d\u5b8c\u6574\u4e4b\u540e\u4ea4\u4e8eShiroFilterFactoryBean\u4f7f\u7528setFilterChainDefinitionMap\u4f7f\u5f97\u8fc7\u6ee4\u751f\u6548<\/p>\n<h4>\u30104\u3011\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668<\/h4>\n<p>\u4e0a\u9762\u6211\u4eec\u4f7f\u7528\u4e86shiro\u7684\u9ed8\u8ba4\u8fc7\u6ee4\u5668\uff0c\u4f46\u662f\u7531\u4e8e\u4e1a\u52a1\u9700\u6c42\uff0c\u54b1\u4eec\u53ef\u80fd\u8981\u5b9a\u4e49\u81ea\u5df1\u7684\u8fc7\u6ee4\u5668\uff0c\u90a3\u4e48\u54b1\u4eec\u5b9a\u4e49\u5462\uff1f<\/p>\n<p>\u8fd9\u91cc\u6211\u4eec\u5148\u67e5\u770bRolesAuthorizationFilter<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581071730065.png\" alt=\"1581071730065\" \/><\/p>\n<p>\u5206\u6790\uff1a\u6539\u6e90\u7801\u8868\u793a\uff0c\u4f8b\u5982\uff1a\/admin\/order= roles[&#8220;admin, root&#8221;] \uff0c\u53ea\u6709\u5f53\u653e\u95ee\u8be5\u63a5\u53e3\u540c\u65f6\u5177\u5907admin\u548croot\u4e24\u79cd\u89d2\u8272\u65f6\uff0c\u624d\u53ef\u4ee5\u88ab\u8bbf\u95ee\u3002<\/p>\n<h4>\u30105\u3011\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u4f7f\u7528<\/h4>\n<h5>\u30105.1\u3011\u9700\u6c42<\/h5>\n<pre><code class=\"line-numbers\">1\u3001\u5b9e\u73b0\u53ea\u8981\u6709\u5176\u4e2d\u4e00\u4e2a\u89d2\u8272\uff0c\u5219\u53ef\u8bbf\u95ee\u5bf9\u5e94\u8def\u5f84\n\n<\/code><\/pre>\n<h5>\u30105.2\u3011RolesOrAuthorizationFilter<\/h5>\n<p>\u65b0\u5efafilter\u5c42\uff0c\u65b0\u5efa\u7c7bRolesOrAuthorizationFilter<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.filter;\n\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.util.CollectionUtils;\nimport org.apache.shiro.web.filter.authz.AuthorizationFilter;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.IOException;\nimport java.util.Set;\n\n\/**\n * @Description\uff1a\u89d2\u8272\u6216\u5173\u7cfb\n *\/\npublic class RolesOrAuthorizationFilter extends AuthorizationFilter {\n\n    \/\/TODO - complete JavaDoc\n\n    @SuppressWarnings({\"unchecked\"})\n    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {\n\n        Subject subject = getSubject(request, response);\n        String[] rolesArray = (String[]) mappedValue;\n\n        if (rolesArray == null || rolesArray.length == 0) {\n            \/\/no roles specified, so nothing to check - allow access.\n            return true;\n        }\n\n        Set&lt;String&gt; roles = CollectionUtils.asSet(rolesArray);\n        \/\/\u5faa\u73afroles\u5224\u65ad\u53ea\u8981\u6709\u89d2\u8272\u5219\u8fd4\u56detrue\n        for (String role : roles) {\n            if(subject.hasRole(role)){\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n\n\n<\/code><\/pre>\n<h5>\u30105.3\u3011\u7f16\u8f91ShiroConfig<\/h5>\n<p>\u5728ShiroConfig\u7c7b\u4e2d\u6dfb\u52a0\u5982\u4e0b\u5185\u5bb9<\/p>\n<pre><code class=\"language-java line-numbers\">\/**\n     * @Description \u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u5b9a\u4e49\n     *\/\n    private Map&lt;String, Filter&gt; filters() {\n        Map&lt;String, Filter&gt; map = new HashMap&lt;String, Filter&gt;();\n        map.put(\"role-or\", new RolesOrAuthorizationFilter());\n        return map;\n    }\n\n    \/**\n     * @Description Shiro\u8fc7\u6ee4\u5668\n     *\/\n    @Bean(\"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilterFactoryBean(){\n        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(defaultWebSecurityManager());\n        \/\/\u4f7f\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u751f\u6548\n        shiroFilter.setFilters(filters());\n        shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());\n        shiroFilter.setLoginUrl(\"\/login\");\n        shiroFilter.setUnauthorizedUrl(\"\/login\");\n        return shiroFilter;\n    }\n\n<\/code><\/pre>\n<p>\u30102.2.3\u3011\u7f16\u8f91authentication.properties<\/p>\n<pre><code class=\"language-ini line-numbers\">#\u9759\u6001\u8d44\u6e90\u4e0d\u8fc7\u6ee4\n\/static\/**=anon\n#\u767b\u5f55\u94fe\u63a5\u4e0d\u8fc7\u6ee4\n\/login\/**=anon\n#\u8bbf\u95ee\/resource\/**\u9700\u8981\u6709admin\u7684\u89d2\u8272\n\/resource\/**=role-or[admin]\n#\u5176\u4ed6\u94fe\u63a5\u662f\u9700\u8981\u767b\u5f55\u7684\n\/**=authc\n\n<\/code><\/pre>\n<h3>7\u3001\u6ce8\u89e3\u65b9\u5f0f\u9274\u6743<\/h3>\n<h4>\u30101\u3011\u6ce8\u89e3\u4ecb\u7ecd<\/h4>\n<p>\u4ee5\u4e0b\u4e3a\u5e38\u7528\u6ce8\u89e3<\/p>\n<table>\n<thead>\n<tr>\n<th>\u6ce8\u89e3<\/th>\n<th>\u8bf4\u660e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>@RequiresAuthentication<\/td>\n<td>\u8868\u660e\u5f53\u524d\u7528\u6237\u9700\u662f\u7ecf\u8fc7\u8ba4\u8bc1\u7684\u7528\u6237<\/td>\n<\/tr>\n<tr>\n<td>@ RequiresGuest<\/td>\n<td>\u8868\u660e\u8be5\u7528\u6237\u9700\u4e3a\u201dguest\u201d\u7528\u6237<\/td>\n<\/tr>\n<tr>\n<td>@RequiresPermissions<\/td>\n<td>\u5f53\u524d\u7528\u6237\u9700\u62e5\u6709\u6307\u5b9a\u6743\u9650<\/td>\n<\/tr>\n<tr>\n<td>@RequiresRoles<\/td>\n<td>\u5f53\u524d\u7528\u6237\u9700\u62e5\u6709\u6307\u5b9a\u89d2\u8272<\/td>\n<\/tr>\n<tr>\n<td>@ RequiresUser<\/td>\n<td>\u5f53\u524d\u7528\u6237\u9700\u4e3a\u5df2\u8ba4\u8bc1\u7528\u6237\u6216\u5df2\u8bb0\u4f4f\u7528\u6237<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u4f8b\u5982RoleAction\u7c7b\u4e2d\u6211\u4eec\u6dfb\u52a0<\/p>\n<pre><code class=\"language-java line-numbers\">\/**\n     *@Description: \u8df3\u8f6c\u5230\u89d2\u8272\u7684\u521d\u59cb\u5316\u9875\u9762\n     *\/\n    @RequiresRoles(value ={\"SuperAdmin\",\"dev\"},logical = Logical.OR)\n    @RequestMapping(value = \"listInitialize\")\n    public ModelAndView listInitialize(){\n        return  new ModelAndView(\"\/role\/role-listInitialize\");\n    }\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u6ce8\u89e3\u539f\u7406\u5206\u6790<\/h4>\n<h4>\u30102.1\u3011\u88c5\u8f7d\u8fc7\u7a0b<\/h4>\n<h4>\u30102.2\u3011\u8c03\u7528\u8fc7\u7a0b<\/h4>\n<h2>\u7b2c\u516d\u7ae0 Realm\u7f13\u5b58\u673a\u5236<\/h2>\n<h3>1\u3001Realm\u7f13\u5b58\u673a\u5236\u610f\u4e49<\/h3>\n<p>\u5728\u4e0a\u9762\u6211\u4eec\u81ea\u5b9a\u4e86\u81ea\u5df1\u7684realm\uff0c\u4f46\u662f\u6211\u4eec\u53d1\u73b0<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581758782223.png\" alt=\"1581758782223\" \/><\/p>\n<p>\u5728\u8ba4\u8bc1\u548c\u6388\u6743\u7684\u65f6\u5019\uff0c\u7a0b\u5e8f\u9700\u8981\u9891\u7e41\u7684\u8bbf\u95ee\u6570\u636e\u5e93\uff0c\u8fd9\u6837\u5bf9\u4e8e\u6570\u636e\u5e93\u7684\u538b\u529b\u53ef\u60f3\u800c\u77e5\uff0c\u90a3\u6211\u4eec\u600e\u4e48\u5904\u7406\u5462\uff1f<\/p>\n<h3>2\u3001Realm\u7f13\u5b58\u673a\u5236\u5b9e\u73b0\u601d\u8def<\/h3>\n<h4>\u30101\u3011\u7f13\u5b58\u673a\u5236\u56fe\u89e3<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1584067476241.png\" alt=\"1584067476241\" \/><\/p>\n<h4>\u30102\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p>\u6b64\u65f6\u6211\u4eec\u5bf9UserBridgeServiceImpl\u7684\u5b9e\u73b0\u7c7b\u91cc\u9762\u7684\u903b\u8f91\u52a0\u5165\u4e86\u81ea\u5b9a\u4e49\u7684SimpleCacheService\u7f13\u5b58\u670d\u52a1\u63a5\u53e3\uff0c\u7b80\u5355\u6765\u8bf4\u5b9e\u73b0\u4e86\u5728\u8ba4\u8bc1\u548c\u9274\u6743\u65f6\u4e0d\u9700\u8981\u6bcf\u6b21\u90fd\u53bb\u67e5\u8be2\u6570\u636e\u5e93\uff0c\u800c\u662f\u628a\u8ba4\u8bc1\u548c\u9274\u6743\u4fe1\u606f\u653e\u5165\u5230redis\u7f13\u5b58\u4e2d\uff0c\u4ee5\u51cf\u4f4e\u6570\u636e\u5e93\u7684\u8bbf\u95ee\u538b\u529b<\/p>\n<pre><code class=\"language-properties line-numbers\">1\u3001\u96c6\u6210redis\u670d\u52a1\u5668\uff0c\u4f5c\u4e3a\u96c6\u4e2d\u5b58\u50a8\u8ba4\u8bc1\u548c\u9274\u6743\u4fe1\u606f\n2\u3001\u6539\u5199UserBridgeServiceImpl\u4f7f\u5176\u4f18\u5148\u4ece\u7f13\u5b58\u4e2d\u8bfb\u53d6\n\n<\/code><\/pre>\n<h3>3\u3001redission\u96c6\u6210<\/h3>\n<h4>\u30101\u3011\u6dfb\u52a0ShiroRedisProperties<\/h4>\n<p>\u6b64\u7c7b\u4e3b\u8981\u8d1f\u8d23yaml\u6587\u4ef6\u7684\u914d\u7f6e\u7c7b<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\n\n\/**\n * @Description  redis\u914d\u7f6e\u6587\u4ef6\n *\/\n@Data\n@ConfigurationProperties(prefix = \"itheima.framework.shiro.redis\")\npublic class ShiroRedisProperties implements Serializable {\n\n    \/**\n     * redis\u8fde\u63a5\u5730\u5740\n     *\/\n    private String nodes ;\n\n    \/**\n     * \u83b7\u53d6\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4\n     *\/\n    private int connectTimeout ;\n\n    \/**\n     * \u8fde\u63a5\u6c60\u5927\u5c0f\n     *\/\n    private int connectPoolSize;\n\n    \/**\n     * \u521d\u59cb\u5316\u8fde\u63a5\u6570\n     *\/\n    private int connectionMinimumidleSize ;\n\n    \/**\n     * \u7b49\u5f85\u6570\u636e\u8fd4\u56de\u8d85\u65f6\u65f6\u95f4\n     *\/\n    private int timeout ;\n\n    \/**\n     *  \u5168\u5c40\u8d85\u65f6\u65f6\u95f4\n     *\/\n    private long globalSessionTimeout;\n\n}\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u7f16\u8f91ShiroConfig<\/h4>\n<p>\u96c6\u6210redisson\u7684\u76f8\u5173\u914d\u7f6e\uff0c\u540c\u65f6\u542f\u7528ShiroRedisProperties\u7684\u914d\u7f6e<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\n\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.impl.ShiroDbRealmImpl;\nimport com.itheima.shiro.filter.RolesOrAuthorizationFilter;\nimport com.itheima.shiro.properties.PropertiesUtil;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.redisson.Redisson;\nimport org.redisson.api.RedissonClient;\nimport org.redisson.config.Config;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\nimport javax.servlet.Filter;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description \u6743\u9650\u914d\u7f6e\u7c7b\n *\/\n@Configuration\n@ComponentScan(basePackages = \"com.itheima.shiro.core\")\n@EnableConfigurationProperties({ShiroRedisProperties.class})\n@Log4j2\npublic class ShiroConfig {\n\n    @Autowired\n    private ShiroRedisProperties shiroRedisProperties;\n\n    \/**\n     * @Description redission\u5ba2\u6237\u7aef\n     *\/\n    @Bean(\"redissonClientForShiro\")\n    public RedissonClient redissonClient() {\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5f00\u59cb======\");\n        String[] nodeList = shiroRedisProperties.getNodes().split(\",\");\n        Config config = new Config();\n        if (nodeList.length == 1) {\n            config.useSingleServer().setAddress(nodeList[0])\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        } else {\n            config.useClusterServers().addNodeAddress(nodeList)\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        }\n        RedissonClient redissonClient =  Redisson.create(config);\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5b8c\u6210======\");\n        return redissonClient;\n    }\n\n    \/**\n     * @Description \u521b\u5efacookie\u5bf9\u8c61\n     *\/\n    @Bean(name=\"sessionIdCookie\")\n    public SimpleCookie simpleCookie(){\n        SimpleCookie simpleCookie = new SimpleCookie();\n        simpleCookie.setName(\"ShiroSession\");\n        return simpleCookie;\n    }\n\n    \/**\n     * @Description \u6743\u9650\u7ba1\u7406\u5668\n     * @param\n     * @return\n     *\/\n    @Bean(name=\"securityManager\")\n    public DefaultWebSecurityManager defaultWebSecurityManager(){\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(shiroDbRealm());\n        securityManager.setSessionManager(shiroSessionManager());\n        return securityManager;\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49RealmImpl\n     *\/\n    @Bean(name=\"shiroDbRealm\")\n    public ShiroDbRealm shiroDbRealm(){\n        return new ShiroDbRealmImpl();\n    }\n\n\n    \/**\n     * @Description \u4f1a\u8bdd\u7ba1\u7406\u5668\n     *\/\n    @Bean(name=\"sessionManager\")\n    public DefaultWebSessionManager shiroSessionManager(){\n        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();\n        sessionManager.setSessionValidationSchedulerEnabled(false);\n        sessionManager.setSessionIdCookieEnabled(true);\n        sessionManager.setSessionIdCookie(simpleCookie());\n        sessionManager.setGlobalSessionTimeout(3600000);\n        return sessionManager;\n    }\n\n    \/**\n     * @Description \u4fdd\u8bc1\u5b9e\u73b0\u4e86Shiro\u5185\u90e8lifecycle\u51fd\u6570\u7684bean\u6267\u884c\n     *\/\n    @Bean(name = \"lifecycleBeanPostProcessor\")\n    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    \/**\n     * @Description AOP\u5f0f\u65b9\u6cd5\u7ea7\u6743\u9650\u68c0\u67e5\n     *\/\n    @Bean\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);\n        return defaultAdvisorAutoProxyCreator;\n    }\n\n    \/**\n     * @Description \u914d\u5408DefaultAdvisorAutoProxyCreator\u4e8b\u9879\u6ce8\u89e3\u6743\u9650\u6821\u9a8c\n     *\/\n    @Bean\n    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {\n        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();\n        aasa.setSecurityManager(defaultWebSecurityManager());\n        return new AuthorizationAttributeSourceAdvisor();\n    }\n\n    \/**\n     * @Description \u8fc7\u6ee4\u5668\u94fe\n     *\/\n    private Map&lt;String, String&gt; filterChainDefinition(){\n        List&lt;Object&gt; list  = PropertiesUtil.propertiesShiro.getKeyList();\n        Map&lt;String, String&gt; map = new LinkedHashMap&lt;&gt;();\n        for (Object object : list) {\n            String key = object.toString();\n            String value = PropertiesUtil.getShiroValue(key);\n            log.info(\"\u8bfb\u53d6\u9632\u6b62\u76d7\u94fe\u63a7\u5236\uff1a---key{},---value:{}\",key,value);\n            map.put(key, value);\n        }\n        return map;\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u5b9a\u4e49\n     *\/\n    private Map&lt;String, Filter&gt; filters() {\n        Map&lt;String, Filter&gt; map = new HashMap&lt;String, Filter&gt;();\n        map.put(\"roleOr\", new RolesOrAuthorizationFilter());\n        return map;\n    }\n\n    \/**\n     * @Description Shiro\u8fc7\u6ee4\u5668\n     *\/\n    @Bean(\"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilterFactoryBean(){\n        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(defaultWebSecurityManager());\n        \/\/\u4f7f\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u751f\u6548\n        shiroFilter.setFilters(filters());\n        shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());\n        shiroFilter.setLoginUrl(\"\/login\");\n        shiroFilter.setUnauthorizedUrl(\"\/login\");\n        return shiroFilter;\n    }\n\n}\n\n<\/code><\/pre>\n<h3>4\u3001\u7f13\u5b58\u5bf9\u8c61SimpleMapCache<\/h3>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.base;\n\nimport com.itheima.shiro.utils.EmptyUtil;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheException;\n\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\n\n\n\/**\n * @Description \u7f13\u5b58\u5b9e\u73b0\u7c7b, \u5b9e\u73b0\u5e8f\u5217 \u63a5\u53e3\u65b9\u4fbf\u5bf9\u8c61\u5b58\u50a8\u4e8e\u7b2c\u4e09\u65b9\u5bb9\u5668(Map\u5b58\u653e\u952e\u503c\u5bf9)\n *\/\npublic class SimpleMapCache implements Cache&lt;Object, Object&gt;, Serializable {\n\n    private final Map&lt;Object, Object&gt; attributes;\n\n    private final String name;\n\n    public SimpleMapCache(String name, Map&lt;Object, Object&gt; backingMap) {\n        if (name == null)\n            throw new IllegalArgumentException(\"Cache name cannot be null.\");\n        if (backingMap == null) {\n            throw new IllegalArgumentException(\"Backing map cannot be null.\");\n        } else {\n            this.name = name;\n            attributes = backingMap;\n        }\n    }\n\n    public Object get(Object key) throws CacheException {\n        return attributes.get(key);\n    }\n\n    public Object put(Object key, Object value) throws CacheException {\n        return attributes.put(key, value);\n    }\n\n    public Object remove(Object key) throws CacheException {\n        return attributes.remove(key);\n    }\n\n    public void clear() throws CacheException {\n        attributes.clear();\n    }\n\n    public int size() {\n        return attributes.size();\n    }\n\n    public Set&lt;Object&gt; keys() {\n        Set&lt;Object&gt; keys = attributes.keySet();\n        if (!keys.isEmpty())\n            return Collections.unmodifiableSet(keys);\n        else\n            return Collections.emptySet();\n    }\n\n    public Collection&lt;Object&gt; values() {\n        Collection&lt;Object&gt; values = attributes.values();\n        if (!EmptyUtil.isNullOrEmpty(values))\n            return Collections.unmodifiableCollection(values);\n        else\n            return Collections.emptySet();\n    }\n\n    @Override\n    public String toString() {\n        return \"SimpleMapCache [attributes=\" + attributes + \", name=\" + name\n                + \", keys()=\" + keys() + \", size()=\" + size() + \", values()=\"\n                + values() + \"]\";\n    }\n}\n\n<\/code><\/pre>\n<h3>5\u3001ShiroRedissionSerialize\u5e8f\u5217\u5316\u5de5\u5177<\/h3>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.utils;\n\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.codec.Base64;\n\nimport java.io.*;\n\n\/**\n * @Description\uff1a\u5b9e\u73b0shiro\u4f1a\u8bdd\u7684\u5e8f\u5217\u5316\u5b58\u50a8\n *\/\n@Log4j2\npublic class ShiroRedissionSerialize {\n\n    public static Object deserialize(String str) {\n        if (EmptyUtil.isNullOrEmpty(str)) {\n            return null;\n        }\n        ByteArrayInputStream bis = null;\n        ObjectInputStream ois = null;\n        Object object=null;\n        try {\n            bis = new ByteArrayInputStream(EncodesUtil.decodeBase64(str));\n            ois = new ObjectInputStream(bis);\n            object = ois.readObject();\n        } catch (IOException |ClassNotFoundException e) {\n            log.error(\"\u6d41\u8bfb\u53d6\u5f02\u5e38\uff1a{}\",e);\n        } finally {\n            try {\n                bis.close();\n                ois.close();\n            } catch (IOException e) {\n                log.error(\"\u6d41\u8bfb\u53d6\u5f02\u5e38\uff1a{}\",e);\n            }\n        }\n        return object;\n    }\n\n    public static String serialize(Object obj) {\n\n        if (EmptyUtil.isNullOrEmpty(obj)) {\n            return null;\n        }\n        ByteArrayOutputStream bos = null;\n        ObjectOutputStream oos = null;\n        String base64String = null;\n        try {\n            bos = new ByteArrayOutputStream();\n            oos = new ObjectOutputStream(bos);\n            oos.writeObject(obj);\n            base64String = EncodesUtil.encodeBase64(bos.toByteArray());\n        } catch (IOException e) {\n            log.error(\"\u6d41\u5199\u5165\u5f02\u5e38\uff1a{}\",e);\n        } finally {\n            try {\n                bos.close();\n                oos.close();\n            } catch (IOException e) {\n                log.error(\"\u6d41\u5199\u5165\u5f02\u5e38\uff1a{}\",e);\n            }\n        }\n        return base64String;\n    }\n}\n\n<\/code><\/pre>\n<h3>6\u3001\u7f13\u5b58\u670d\u52a1\u63a5\u53e3SimpleCacheService<\/h3>\n<p>SimpleCacheService<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core;\n\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheException;\n\n\/**\n * @Description \u7b80\u5355\u7684\u7f13\u5b58\u7ba1\u7406\u63a5\u53e3\n *\/\npublic interface SimpleCacheService {\n\n    \/**\n     * &lt;b&gt;\u529f\u80fd\u8bf4\u660e\uff1a&lt;\/b&gt;\uff1a\u65b0\u589e\u7f13\u5b58\u5806\u5230\u7ba1\u7406\u5668&lt;br&gt;\n     *\/\n     void createCache(String cacheName, Cache&lt;Object, Object&gt; cache) throws CacheException;\n\n    \/**\n     * &lt;b&gt;\u65b9\u6cd5\u540d\uff1a&lt;\/b&gt;\uff1agetCache&lt;br&gt;\n     * &lt;b&gt;\u529f\u80fd\u8bf4\u660e\uff1a&lt;\/b&gt;\uff1a\u83b7\u53d6\u7f13\u5b58\u5806&lt;br&gt;\n     *\/\n     Cache&lt;Object, Object&gt; getCache(String cacheName) throws CacheException;\n\n    \/**\n     * &lt;b&gt;\u65b9\u6cd5\u540d\uff1a&lt;\/b&gt;\uff1aremoveCache&lt;br&gt;\n     * &lt;b&gt;\u529f\u80fd\u8bf4\u660e\uff1a&lt;\/b&gt;\uff1a\u79fb\u9664\u7f13\u5b58\u5806&lt;br&gt;\n     *\/\n     void removeCache(String cacheName) throws CacheException;\n\n    \/**\n     * &lt;b&gt;\u65b9\u6cd5\u540d\uff1a&lt;\/b&gt;\uff1aupdateCahce&lt;br&gt;\n     * &lt;b&gt;\u529f\u80fd\u8bf4\u660e\uff1a&lt;\/b&gt;\uff1a\u66f4\u65b0\u7f13\u5b58\u5806&lt;br&gt;\n     *\/\n     void updateCahce(String cacheName, Cache&lt;Object, Object&gt; cache) throws CacheException;\n}\n\n\n<\/code><\/pre>\n<p>SimpleCacheServiceImpl<\/p>\n<p>\u8c03\u7528RedissonClient\u53bb\u5b9e\u73b0\u7f13\u5b58\uff0c\u540c\u65f6\u4f7f\u7528ShiroRedissionSerialize\u5b9e\u73b0\u5e8f\u5217\u5316<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.core.SimpleCacheService;\nimport com.itheima.shiro.utils.ShiroRedissionSerialize;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheException;\nimport org.redisson.api.RBucket;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport java.util.concurrent.TimeUnit;\n\n\n\/**\n *\n * @Description \u7b80\u5355\u7684\u7f13\u5b58\u7ba1\u7406\u63a5\u53e3\u7684\u5b9e\u73b0\n *\/\n@Log4j2\n@Component\npublic class SimpleCacheServiceImpl implements SimpleCacheService {\n\n    @Resource(name = \"redissonClientForShiro\")\n    RedissonClient redissonClient;\n\n    @Override\n    public void createCache(String name, Cache&lt;Object, Object&gt; cache){\n        RBucket&lt;String&gt; bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);\n        bucket.trySet(ShiroRedissionSerialize.serialize(cache), SecurityUtils.getSubject().getSession().getTimeout()\/1000, TimeUnit.SECONDS);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public Cache&lt;Object, Object&gt; getCache(String name) throws CacheException {\n        RBucket&lt;String&gt; bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);\n        return (Cache&lt;Object, Object&gt;) ShiroRedissionSerialize.deserialize(bucket.get());\n    }\n\n    @Override\n    public void removeCache(String name) throws CacheException {\n        RBucket&lt;String&gt; bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);\n        bucket.delete();\n    }\n\n    @Override\n    public void updateCahce(String name, Cache&lt;Object, Object&gt; cache){\n        RBucket&lt;String&gt; bucket =  redissonClient.getBucket(CacheConstant.GROUP_CAS+name);\n        bucket.set(ShiroRedissionSerialize.serialize(cache), SecurityUtils.getSubject().getSession().getTimeout()\/1000, TimeUnit.MILLISECONDS);\n    }\n\n\n}\n\n\n<\/code><\/pre>\n<h3>7\u3001\u6865\u63a5\u5668BridgeService<\/h3>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.bridge;\n\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.pojo.User;\nimport org.apache.shiro.authz.AuthorizationInfo;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7528\u6237\u4fe1\u606f\u6865\u63a5\uff08\u540e\u671f\u4f1a\u505a\u7f13\u5b58\uff09\n *\/\npublic interface UserBridgeService {\n\n\n    \/**\n     * @Description \u67e5\u627e\u7528\u6237\u4fe1\u606f\n     * @param loginName \u7528\u6237\u540d\u79f0\n     * @return user\u5bf9\u8c61\n     *\/\n    User findUserByLoginName(String loginName);\n\n    \/**\n     * @Description \u9274\u6743\u65b9\u6cd5\n     * @param shiroUser \u4ee4\u724c\u5bf9\u8c61\n     * @return \u9274\u6743\u4fe1\u606f\n     *\/\n    AuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser);\n\n    \/**\n     * @Description \u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u89d2\u8272\u6807\u8bc6list\n     * @param userId \u7528\u6237id\n     * @return \u89d2\u8272\u6807\u8bc6\u96c6\u5408\n     *\/\n    List&lt;String&gt; findRoleList(String key,String userId);\n\n    \/**\n     * @Description \u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u8d44\u6e90\u6807\u8bc6list\n     * @param userId \u7528\u6237id\n     * @return \u8d44\u6e90\u6807\u8bc6\u96c6\u5408\n     *\/\n    List&lt;String&gt; findResourcesList(String key,String userId);\n\n    \/**\n     * @Description \u67e5\u8be2\u8d44\u6e90ids\n     * @param userId \u7528\u6237id\n     * @return \u8d44\u6e90id\u96c6\u5408\n     *\/\n    List&lt;String&gt; findResourcesIds(String userId);\n\n    \/**\n     * @Description \u52a0\u8f7d\u7f13\u5b58\n     * @param shiroUser \u4ee4\u724c\u5bf9\u8c61\n     * @return\n     *\/\n    void loadUserAuthorityToCache(ShiroUser shiroUser);\n}\n\n\n<\/code><\/pre>\n<p>\u6b64\u65f6\u6211\u4eec\u5c31\u53ef\u4ee5\u4fee\u6539UserBridgeServiceImpl\u5b9e\u73b0\u7f13\u5b58\u4e86<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.bridge.impl;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.core.SimpleCacheService;\nimport com.itheima.shiro.core.adapter.UserAdapter;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleMapCache;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.pojo.Resource;\nimport com.itheima.shiro.pojo.Role;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.utils.ShiroUtil;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.apache.shiro.cache.Cache;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u7528\u6237\u4fe1\u606f\u6865\u63a5\uff08\u540e\u671f\u4f1a\u505a\u7f13\u5b58\uff09\n *\/\n@Component(\"userBridgeService\")\npublic class UserBridgeServiceImpl implements UserBridgeService {\n\n    @Autowired\n    UserAdapter userAdapter;\n\n    @Autowired\n    SimpleCacheService simpleCacheService;\n\n    @Override\n    public User findUserByLoginName(String loginName) {\n        String key = CacheConstant.FIND_USER_BY_LOGINNAME + loginName;\n        \/\/\u83b7\u53d6\u7f13\u5b58\n        Cache&lt;Object, Object&gt; cache = simpleCacheService.getCache(key);\n        \/\/\u7f13\u5b58\u5b58\u5728\n        if (!EmptyUtil.isNullOrEmpty(cache)){\n            return (User) cache.get(key);\n        }\n        \/\/\u7f13\u5b58\u4e0d\u5b58\u5728\n        User user = userAdapter.findUserByLoginName(loginName);\n        if (!EmptyUtil.isNullOrEmpty(user)){\n            Map&lt;Object,Object&gt; map = new HashMap&lt;&gt;();\n            map.put(key, user);\n            SimpleMapCache simpleMapCache = new SimpleMapCache(key, map);\n            simpleCacheService.creatCache(key, simpleMapCache);\n        }\n        return user;\n    }\n\n    @Override\n    public List&lt;String&gt; findResourcesIds(String userId) {\n        String sessionId = ShiroUtil.getShiroSessionId();\n        String key = CacheConstant.RESOURCES_KEY_IDS+sessionId;\n        List&lt;Resource&gt; resources = new ArrayList&lt;&gt;();\n        \/\/\u83b7\u53d6\u7f13\u5b58\n        Cache&lt;Object, Object&gt; cache = simpleCacheService.getCache(key);\n        \/\/\u7f13\u5b58\u5b58\u5728\n        if (!EmptyUtil.isNullOrEmpty(cache)){\n            resources = (List&lt;Resource&gt;) cache.get(key);\n        }else {\n        \/\/\u7f13\u5b58\u4e0d\u5b58\u5728\n            resources = userAdapter.findResourceByUserId(userId);\n            if (!EmptyUtil.isNullOrEmpty(resources)){\n                Map&lt;Object,Object&gt; map = new HashMap&lt;&gt;();\n                map.put(key, resources);\n                SimpleMapCache simpleMapCache = new SimpleMapCache(key, map);\n                simpleCacheService.creatCache(key,simpleMapCache );\n            }\n\n        }\n\n        List&lt;String&gt; ids = new ArrayList&lt;&gt;();\n        for (Resource resource : resources) {\n            ids.add(resource.getId());\n        }\n        return ids;\n    }\n\n    @Override\n    public AuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser) {\n        String sessionId = ShiroUtil.getShiroSessionId();\n        String roleKey = CacheConstant.ROLE_KEY+sessionId;\n        String resourcesKey = CacheConstant.RESOURCES_KEY+sessionId;\n        \/\/\u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u7684\u89d2\u8272\u6807\u8bc6\n        List&lt;String&gt; roleList = this.findRoleList(roleKey,shiroUser.getId());\n        \/\/\u67e5\u8be2\u7528\u6237\u5bf9\u4e8e\u7684\u8d44\u6e90\u6807\u8bc6\n        List&lt;String&gt; resourcesList = this.findResourcesList(resourcesKey,shiroUser.getId());\n        \/\/\u6784\u5efa\u9274\u6743\u4fe1\u606f\u5bf9\u8c61\n        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();\n        simpleAuthorizationInfo.addRoles(roleList);\n        simpleAuthorizationInfo.addStringPermissions(resourcesList);\n        return simpleAuthorizationInfo;\n    }\n\n    @Override\n    public List&lt;String&gt; findRoleList(String key,String userId){\n        List&lt;Role&gt; roles = new ArrayList&lt;&gt;();\n        \/\/\u83b7\u5f97\u7f13\u5b58\n        Cache&lt;Object, Object&gt; cache = simpleCacheService.getCache(key);\n        \/\/\u7f13\u5b58\u5b58\u5728\n        if (!EmptyUtil.isNullOrEmpty(cache)){\n            roles = (List&lt;Role&gt;) cache.get(key);\n        }else {\n        \/\/\u7f13\u5b58\u4e0d\u5b58\u5728\n            roles = userAdapter.findRoleByUserId(userId);\n            if (!EmptyUtil.isNullOrEmpty(roles)){\n                Map&lt;Object,Object&gt; map = new HashMap&lt;&gt;();\n                map.put(key, roles);\n                SimpleMapCache simpleMapCache = new SimpleMapCache(key, map);\n                simpleCacheService.creatCache(key,simpleMapCache );\n            }\n        }\n\n        List&lt;String&gt; roleLabel = new ArrayList&lt;&gt;();\n        for (Role role : roles) {\n            roleLabel.add(role.getLabel());\n        }\n        return roleLabel;\n    }\n\n    @Override\n    public List&lt;String&gt; findResourcesList(String key,String userId){\n        List&lt;Resource&gt; resources = new ArrayList&lt;&gt;();\n        \/\/\u83b7\u5f97\u7f13\u5b58\n        Cache&lt;Object, Object&gt; cache = simpleCacheService.getCache(key);\n        \/\/\u7f13\u5b58\u5b58\u5728\n        if (!EmptyUtil.isNullOrEmpty(cache)){\n            resources = (List&lt;Resource&gt;) cache.get(key);\n        }else {\n            \/\/\u7f13\u5b58\u4e0d\u5b58\u5728\n            resources = userAdapter.findResourceByUserId(userId);\n            if (!EmptyUtil.isNullOrEmpty(resources)){\n                Map&lt;Object,Object&gt; map = new HashMap&lt;&gt;();\n                map.put(key, resources);\n                SimpleMapCache simpleMapCache = new SimpleMapCache(key, map);\n                simpleCacheService.creatCache(key,simpleMapCache );\n            }\n        }\n        List&lt;String&gt; resourceLabel = new ArrayList&lt;&gt;();\n        for (Resource resource : resources) {\n            resourceLabel.add(resource.getLabel());\n        }\n        return resourceLabel;\n    }\n\n\n\n\n    @Override\n    public void loadUserAuthorityToCache(ShiroUser shiroUser) {\n        String sessionId = ShiroUtil.getShiroSessionId();\n        String roleKey = CacheConstant.ROLE_KEY+sessionId;\n        String resourcesKey = CacheConstant.RESOURCES_KEY+sessionId;\n        \/\/\u67e5\u8be2\u7528\u6237\u5bf9\u5e94\u7684\u89d2\u8272\u6807\u8bc6\n        List&lt;String&gt; roleList = this.findRoleList(roleKey,shiroUser.getId());\n        \/\/\u67e5\u8be2\u7528\u6237\u5bf9\u4e8e\u7684\u8d44\u6e90\u6807\u8bc6\n        List&lt;String&gt; resourcesList = this.findResourcesList(resourcesKey,shiroUser.getId());\n    }\n}\n\n<\/code><\/pre>\n<h3>8\u3001\u6d4b\u8bd5<\/h3>\n<p>\u4f7f\u7528debug\u6a21\u5f0f\u542f\u52a8\u9879\u76ee\uff0c\u4f7f\u7528admin\/pass\u767b\u5f55\u7cfb\u7edf\uff0c\u8bbf\u95ee\u8d44\u6e90\uff0c\u8fdb\u5165debug\u6a21\u5f0f<\/p>\n<p>\u7b2c\u4e00\u6b21\u8bbf\u95ee\u8d70\u6570\u636e\u5e93<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581845508601.png\" alt=\"1581845508601\" \/><\/p>\n<p>\u7b2c\u4e8c\u6b21\u8d70\u7f13\u5b58<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581845570053.png\" alt=\"1581845570053\" \/><\/p>\n<h3>9\u3001\u7f13\u5b58\u7684\u6e05\u7406<\/h3>\n<p>\u6211\u4eec\u5b9e\u73b0\u7684realm\u7684\u96c6\u4e2d\u5f0f\u7f13\u5b58\uff0c\u90a3\u4e48\u8fd8\u6709\u4ec0\u4e48\u95ee\u9898\u6ca1\u6709\u89e3\u51b3\u5462\uff1f<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1584603830411.png\" alt=\"1584603830411\" \/><\/p>\n<p>\u7528\u6237\u5728\u70b9\u51fb\u9000\u51fa\u65f6\u5019\uff0c\u6211\u4eec\u8fd8\u6ca1\u6709\u6e05\u7406\u7f13\u5b58\uff01\u5982\u679c\u4e0d\u6e05\u7406\uff0c\u5728\u7528\u6237\u91cf\u5927\u7684\u65f6\u5019\uff0c\u53ef\u80fd\u4f1a\u6709\u5927\u91cf\u7684\u5783\u573e\u4fe1\u606f\u5728redis\u4e2d\u5b58\u5728\u3002<\/p>\n<p>\u91cd\u5199ShiroConfig<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.constant.SuperConstant;\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.SimpleCacheService;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleToken;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.utils.ShiroUtil;\nimport org.apache.shiro.authc.*;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.apache.shiro.util.ByteSource;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49realm\u7684\u62bd\u8c61\u7c7b\u5b9e\u73b0\n *\/\npublic class ShiroDbRealmImpl extends ShiroDbRealm {\n\n    @Autowired\n    UserBridgeService userBridgeService;\n\n    @Autowired\n    SimpleCacheService simpleCacheService;\n\n    @Override\n    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {\n        \/\/token\u4ee4\u724c\u4fe1\u606f\n        SimpleToken simpleToken = (SimpleToken) token;\n        \/\/\u67e5\u8be2user\u5bf9\u8c61\n        User user = userBridgeService.findUserByLoginName(simpleToken.getUsername());\n        if (EmptyUtil.isNullOrEmpty(user)){\n            throw new UnknownAccountException(\"\u8d26\u53f7\u4e0d\u5b58\u5728\uff01\");\n        }\n        \/\/\u6784\u5efa\u8ba4\u8bc1\u4ee4\u724c\u5bf9\u8c61\n        ShiroUser shiroUser = BeanConv.toBean(user, ShiroUser.class);\n        shiroUser.setResourceIds(userBridgeService.findResourcesIds(shiroUser.getId()));\n        String slat  = shiroUser.getSalt();\n        String password = shiroUser.getPassWord();\n        \/\/\u6784\u5efa\u8ba4\u8bc1\u4fe1\u606f\u5bf9\u8c61:1\u3001\u4ee4\u724c\u5bf9\u8c61 2\u3001\u5bc6\u6587\u5bc6\u7801  3\u3001\u52a0\u5bc6\u56e0\u5b50 4\u3001\u5f53\u524drealm\u7684\u540d\u79f0\n        return new SimpleAuthenticationInfo(shiroUser, password, ByteSource.Util.bytes(slat), getName());\n    }\n\n    @Override\n    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();\n        return userBridgeService.getAuthorizationInfo(shiroUser);\n    }\n\n    @Override\n    protected void doClearCache(PrincipalCollection principals) {\n        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();\n        String sessionId = ShiroUtil.getShiroSessionId();\n        String roleKey = CacheConstant.ROLE_KEY+sessionId;\n        String resourcesKey = CacheConstant.RESOURCES_KEY+sessionId;\n        String loginNamekey = CacheConstant.FIND_USER_BY_LOGINNAME + shiroUser.getLoginName();\n        String resourcesIdKey = CacheConstant.RESOURCES_KEY_IDS+sessionId;\n        simpleCacheService.removeCache(roleKey);\n        simpleCacheService.removeCache(resourcesKey);\n        simpleCacheService.removeCache(loginNamekey);\n        simpleCacheService.removeCache(resourcesIdKey);\n        super.doClearCache(principals);\n    }\n\n    @Override\n    public void initCredentialsMatcher() {\n        \/\/\u6307\u5b9a\u5bc6\u7801\u7b97\u6cd5\n        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(SuperConstant.HASH_ALGORITHM);\n        \/\/\u6307\u5b9a\u8fed\u4ee3\u6b21\u6570\n        hashedCredentialsMatcher.setHashIterations(SuperConstant.HASH_INTERATIONS);\n        \/\/\u751f\u6548\u5bc6\u7801\u6bd4\u8f83\u5668\n        setCredentialsMatcher(hashedCredentialsMatcher);\n    }\n}\n\n\n<\/code><\/pre>\n<h2>\u7b2c\u4e03\u7ae0 \u5b9e\u73b0\u5206\u5e03\u5f0f\u4f1a\u8bddSessionManager<\/h2>\n<h3>1\u3001\u4f1a\u8bdd\u7684\u95ee\u9898<\/h3>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581846589128.png\" alt=\"1581846589128\" \/><\/p>\n<h3>2\u3001\u5206\u5e03\u5f0f\u4f1a\u8bdd\u5b9e\u73b0\u601d\u8def<\/h3>\n<h4>\u30101\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p>\u200b       \u6240\u6709\u670d\u52a1\u5668\u7684session\u4fe1\u606f\u90fd\u5b58\u50a8\u5230\u4e86\u540c\u4e00\u4e2aRedis\u96c6\u7fa4\u4e2d\uff0c\u5373\u6240\u6709\u7684\u670d\u52a1\u90fd\u5c06 Session \u7684\u4fe1\u606f\u5b58\u50a8\u5230 Redis \u96c6\u7fa4\u4e2d\uff0c\u65e0\u8bba\u662f\u5bf9 Session \u7684\u6ce8\u9500\u3001\u66f4\u65b0\u90fd\u4f1a\u540c\u6b65\u5230\u96c6\u7fa4\u4e2d\uff0c\u8fbe\u5230\u4e86 Session \u5171\u4eab\u7684\u76ee\u7684\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581846769926.png\" alt=\"1581846769926\" \/><\/p>\n<p>\u200b       Cookie \u4fdd\u5b58\u5728\u5ba2\u6237\u7aef\u6d4f\u89c8\u5668\u4e2d\uff0c\u800c Session \u4fdd\u5b58\u5728\u670d\u52a1\u5668\u4e0a\u3002\u5ba2\u6237\u7aef\u6d4f\u89c8\u5668\u8bbf\u95ee\u670d\u52a1\u5668\u7684\u65f6\u5019\uff0c\u670d\u52a1\u5668\u628a\u5ba2\u6237\u7aef\u4fe1\u606f\u4ee5\u67d0\u79cd\u5f62\u5f0f\u8bb0\u5f55\u5728\u670d\u52a1\u5668\u4e0a\uff0c\u8fd9\u5c31\u662f Session\u3002\u5ba2\u6237\u7aef\u6d4f\u89c8\u5668\u518d\u6b21\u8bbf\u95ee\u65f6\u53ea\u9700\u8981\u4ece\u8be5 Session \u4e2d\u67e5\u627e\u8be5\u5ba2\u6237\u7684\u72b6\u6001\u5c31\u53ef\u4ee5\u4e86\u3002<\/p>\n<p>\u200b       \u5728\u5b9e\u9645\u5de5\u4f5c\u4e2d\u6211\u4eec\u5efa\u8bae\u4f7f\u7528\u5916\u90e8\u7684\u7f13\u5b58\u8bbe\u5907(\u5305\u62ecRedis)\u6765\u5171\u4eab Session\uff0c\u907f\u514d\u5355\u4e2a\u670d\u52a1\u5668\u8282\u70b9\u6302\u6389\u800c\u5f71\u54cd\u670d\u52a1\uff0c\u5171\u4eab\u6570\u636e\u90fd\u4f1a\u653e\u5230\u5916\u90e8\u7f13\u5b58\u5bb9\u5668\u4e2d<\/p>\n<h4>\u30102\u3011\u8bbe\u8ba1\u7c7b\u56fe\u8be6\u89e3<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1584524503148.png\" alt=\"1584524503148\" \/><\/p>\n<h3>3\u3001RedisSessionDao<\/h3>\n<p>RedisSessionDao\u7ee7\u627fAbstractSessionDAO\uff0c\u91cd\u5199\u4e86\u4f1a\u8bdd\u7684\u521b\u5efa\u3001\u8bfb\u53d6\u3001\u4fee\u6539\u7b49\u64cd\u4f5c\uff0c\u5168\u90e8\u7f13\u5b58\u4e0eredis\u4e2d<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.utils.ShiroRedissionSerialize;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.session.mgt.eis.AbstractSessionDAO;\nimport org.redisson.api.RBucket;\nimport org.redisson.api.RedissonClient;\n\nimport javax.annotation.Resource;\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\n\n\/**\n * @Description \u5b9e\u73b0shiro session\u7684memcached\u96c6\u4e2d\u5f0f\u7ba1\u7406~\n *\/\n@Log4j2\npublic class RedisSessionDao extends AbstractSessionDAO {\n\n    @Resource(name = \"redissonClientForShiro\")\n    RedissonClient redissonClient;\n\n    private Long globalSessionTimeout;\n\n    @Override\n    protected Serializable doCreate(Session session) {\n        Serializable sessionId = generateSessionId(session);\n        assignSessionId(session, sessionId);\n\/\/      log.info(\"=============\u521b\u5efasessionId:{}\",sessionId);\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString());\n        sessionIdRBucket.trySet(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);\n        return sessionId;\n    }\n\n    @Override\n    protected Session doReadSession(Serializable sessionId) {\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString());\n        Session session = (Session) ShiroRedissionSerialize.deserialize(sessionIdRBucket.get());\n\/\/      log.info(\"=============\u8bfb\u53d6sessionId:{}\",session.getId().toString());\n        return session;\n    }\n\n    @Override\n    public void delete(Session session) {\n\/\/      log.info(\"=============\u5220\u9664sessionId:{}\",session.getId().toString());\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString());\n        sessionIdRBucket.delete();\n    }\n\n    @Override\n    public Collection&lt;Session&gt; getActiveSessions() {\n        return Collections.emptySet();  \n    }\n\n    @Override\n    public void update(Session session) {\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString());\n        sessionIdRBucket.set(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);\n\/\/      log.info(\"=============\u4fee\u6539sessionId:{}\",session.getId().toString());\n    }\n\n    public void setGlobalSessionTimeout(Long globalSessionTimeout) {\n        this.globalSessionTimeout = globalSessionTimeout;\n    }\n}\n\n\n\n<\/code><\/pre>\n<h3>4\u3001\u91cd\u5199ShiroConfig<\/h3>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\n\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.impl.RedisSessionDao;\nimport com.itheima.shiro.core.impl.ShiroCacheManager;\nimport com.itheima.shiro.core.impl.ShiroDbRealmImpl;\nimport com.itheima.shiro.filter.RolesOrAuthorizationFilter;\nimport com.itheima.shiro.properties.PropertiesUtil;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.session.mgt.eis.SessionDAO;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.redisson.Redisson;\nimport org.redisson.api.RedissonClient;\nimport org.redisson.config.Config;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\nimport javax.servlet.Filter;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description \u6743\u9650\u914d\u7f6e\u7c7b\n *\/\n@Configuration\n@ComponentScan(basePackages = \"com.itheima.shiro.core\")\n@EnableConfigurationProperties({ShiroRedisProperties.class})\n@Log4j2\npublic class ShiroConfig {\n\n    @Autowired\n    private ShiroRedisProperties shiroRedisProperties;\n\n    \/**\n     * @Description redission\u5ba2\u6237\u7aef\n     *\/\n    @Bean(\"redissonClientForShiro\")\n    public RedissonClient redissonClient() {\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5f00\u59cb======\");\n        String[] nodeList = shiroRedisProperties.getNodes().split(\",\");\n        Config config = new Config();\n        if (nodeList.length == 1) {\n            config.useSingleServer().setAddress(nodeList[0])\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        } else {\n            config.useClusterServers().addNodeAddress(nodeList)\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        }\n        RedissonClient redissonClient =  Redisson.create(config);\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5b8c\u6210======\");\n        return redissonClient;\n    }\n\n    \/**\n     * @Description \u521b\u5efacookie\u5bf9\u8c61\n     *\/\n    @Bean(name=\"sessionIdCookie\")\n    public SimpleCookie simpleCookie(){\n        SimpleCookie simpleCookie = new SimpleCookie();\n        simpleCookie.setName(\"ShiroSession\");\n        return simpleCookie;\n    }\n    \/**\n     * @Description \u6743\u9650\u7ba1\u7406\u5668\n     * @param\n     * @return\n     *\/\n    @Bean(name=\"securityManager\")\n    public DefaultWebSecurityManager defaultWebSecurityManager(){\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(shiroDbRealm());\n        securityManager.setSessionManager(shiroSessionManager());\n        return securityManager;\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49RealmImpl\n     *\/\n    @Bean(name=\"shiroDbRealm\")\n    public ShiroDbRealm shiroDbRealm(){\n        return new ShiroDbRealmImpl();\n    }\n\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49session\u4f1a\u8bdd\u5b58\u50a8\u7684\u5b9e\u73b0\u7c7b \uff0c\u4f7f\u7528Redis\u6765\u5b58\u50a8\u5171\u4eabsession\uff0c\u8fbe\u5230\u5206\u5e03\u5f0f\u90e8\u7f72\u76ee\u7684\n     *\/\n    @Bean(\"redisSessionDao\")\n    public SessionDAO redisSessionDao(){\n        RedisSessionDao sessionDAO =   new RedisSessionDao();\n        sessionDAO.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());\n        return sessionDAO;\n    }\n\n    \/**\n     * @Description \u4f1a\u8bdd\u7ba1\u7406\u5668\n     *\/\n    @Bean(name=\"sessionManager\")\n    public DefaultWebSessionManager shiroSessionManager(){\n        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();\n        sessionManager.setSessionDAO(redisSessionDao());\n        sessionManager.setSessionValidationSchedulerEnabled(false);\n        sessionManager.setSessionIdCookieEnabled(true);\n        sessionManager.setSessionIdCookie(simpleCookie());\n        sessionManager.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());\n        return sessionManager;\n    }\n\n    \/**\n     * @Description \u4fdd\u8bc1\u5b9e\u73b0\u4e86Shiro\u5185\u90e8lifecycle\u51fd\u6570\u7684bean\u6267\u884c\n     *\/\n    @Bean(name = \"lifecycleBeanPostProcessor\")\n    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    \/**\n     * @Description AOP\u5f0f\u65b9\u6cd5\u7ea7\u6743\u9650\u68c0\u67e5\n     *\/\n    @Bean\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);\n        return defaultAdvisorAutoProxyCreator;\n    }\n\n    \/**\n     * @Description \u914d\u5408DefaultAdvisorAutoProxyCreator\u4e8b\u9879\u6ce8\u89e3\u6743\u9650\u6821\u9a8c\n     *\/\n    @Bean\n    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {\n        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();\n        aasa.setSecurityManager(defaultWebSecurityManager());\n        return new AuthorizationAttributeSourceAdvisor();\n    }\n\n    \/**\n     * @Description \u8fc7\u6ee4\u5668\u94fe\n     *\/\n    private Map&lt;String, String&gt; filterChainDefinition(){\n        List&lt;Object&gt; list  = PropertiesUtil.propertiesShiro.getKeyList();\n        Map&lt;String, String&gt; map = new LinkedHashMap&lt;&gt;();\n        for (Object object : list) {\n            String key = object.toString();\n            String value = PropertiesUtil.getShiroValue(key);\n            log.info(\"\u8bfb\u53d6\u9632\u6b62\u76d7\u94fe\u63a7\u5236\uff1a---key{},---value:{}\",key,value);\n            map.put(key, value);\n        }\n        return map;\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u5b9a\u4e49\n     *\/\n    private Map&lt;String, Filter&gt; filters() {\n        Map&lt;String, Filter&gt; map = new HashMap&lt;String, Filter&gt;();\n        map.put(\"roleOr\", new RolesOrAuthorizationFilter());\n        return map;\n    }\n\n    \/**\n     * @Description Shiro\u8fc7\u6ee4\u5668\n     *\/\n    @Bean(\"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilterFactoryBean(){\n        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(defaultWebSecurityManager());\n        \/\/\u4f7f\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u751f\u6548\n        shiroFilter.setFilters(filters());\n        shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());\n        shiroFilter.setLoginUrl(\"\/login\");\n        shiroFilter.setUnauthorizedUrl(\"\/login\");\n        return shiroFilter;\n    }\n\n}\n\n\n<\/code><\/pre>\n<h3>5\u3001\u6d4b\u8bd5<\/h3>\n<p>\u6b64\u65f6\u6211\u4eec\u9700\u89812\u4e2a\u76f8\u540c\u7684\u9879\u76eeshiro-day01-12shiro-redis-SessionManager-A\u548cshiro-day01-13shiro-redis-SessionManager-B<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581929726816.png\" alt=\"1581929726816\" \/><\/p>\n<p>\u5206\u522b\u542f\u52a8A,B2\u4e2a\u9879\u76ee<\/p>\n<p>\u8bbf\u95eehttp:\/\/127.0.0.1:8081\/shiro\/login\uff0c\u4f7f\u7528admin\/pass\u767b\u5f55<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581929790783.png\" alt=\"1581929790783\" \/><\/p>\n<p>\u4fee\u6539\u5730\u5740\u680fhttp:\/\/127.0.0.1:8081\/shiro\/menus\/system\u4e3ahttp:\/\/127.0.0.1:8082\/shiro\/menus\/system\uff0c\u4e5f\u53ef\u4ee5\u6b63\u5e38\u8bbf\u95ee<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581929843249.png\" alt=\"1581929843249\" \/><\/p>\n<p>\u6b64\u65f6\u6211\u4eec\u5b9e\u73b0\u4e86\u5728A\u670d\u52a1\u767b\u5f55\uff0c\u76f4\u63a5\u8bbf\u95eeB\u670d\u52a1\u5219\u65e0\u9700\u767b\u5f55<\/p>\n<h2>\u7b2c\u516b\u7ae0 \u9650\u5236\u5bc6\u7801\u91cd\u8bd5\u6b21\u6570<\/h2>\n<h3>1\u3001\u5b9e\u73b0\u539f\u7406<\/h3>\n<p>\u4fdd\u8bc1\u539f\u5b50\u6027\uff1a<\/p>\n<p>\u200b       \u5355\u7cfb\u7edf\uff1aAtomicLong\u8ba1\u6570<\/p>\n<p>\u200b       \u96c6\u7fa4\u7cfb\u7edf\uff1aRedissionClient\u63d0\u4f9b\u7684RAtomicLong\u8ba1\u6570<\/p>\n<pre><code class=\"language-properties line-numbers\">1\u3001\u83b7\u53d6\u7cfb\u7edf\u4e2d\u662f\u5426\u5df2\u6709\u767b\u5f55\u6b21\u6570\u7f13\u5b58,\u7f13\u5b58\u5bf9\u8c61\u7ed3\u6784\u9884\u671f\u4e3a\uff1a\"\u7528\u6237\u540d--\u767b\u5f55\u6b21\u6570\"\u3002\n\n2\u3001\u5982\u679c\u4e4b\u524d\u6ca1\u6709\u767b\u5f55\u7f13\u5b58\uff0c\u5219\u521b\u5efa\u4e00\u4e2a\u767b\u5f55\u6b21\u6570\u7f13\u5b58\u3002\n\n3\u3001\u5982\u679c\u7f13\u5b58\u6b21\u6570\u5df2\u7ecf\u8d85\u8fc7\u9650\u5236\uff0c\u5219\u9a73\u56de\u672c\u6b21\u767b\u5f55\u8bf7\u6c42\u3002\n\n4\u3001\u5c06\u7f13\u5b58\u8bb0\u5f55\u7684\u767b\u5f55\u6b21\u6570\u52a01,\u8bbe\u7f6e\u6307\u5b9a\u65f6\u95f4\u5185\u6709\u6548\n\n5\u3001\u9a8c\u8bc1\u7528\u6237\u672c\u6b21\u8f93\u5165\u7684\u5e10\u53f7\u5bc6\u7801\uff0c\u5982\u679c\u767b\u5f55\u767b\u5f55\u6210\u529f\uff0c\u5219\u6e05\u9664\u6389\u767b\u5f55\u6b21\u6570\u7684\u7f13\u5b58\n\n\n<\/code><\/pre>\n<p>\u601d\u8def\u6709\u4e86\uff0c\u90a3\u6211\u4eec\u5728\u54ea\u91cc\u5b9e\u73b0\u5462\uff1f\u6211\u4eec\u77e5\u9053AuthenticatingRealm\u91cc\u6709\u6bd4\u8f83\u5bc6\u7801\u7684\u5165\u53e3doCredentialsMatch\u65b9\u6cd5<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581930861293.png\" alt=\"1581930861293\" \/><\/p>\n<p>\u67e5\u770b\u5176\u5b9e\u73b0<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581930945007.png\" alt=\"1581930945007\" \/><\/p>\n<h3>2\u3001\u81ea\u5b9a\u4e49\u5bc6\u7801\u6bd4\u8f83\u5668<\/h3>\n<p>\u65b0\u5efa\u9879\u76eeshiro-day01-14shiro-RetryLimit<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581934188203.png\" alt=\"1581934188203\" \/><\/p>\n<h4>\u30101\u3011RetryLimitCredentialsMatcher<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.core.base.ShiroUser;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.ExcessiveAttemptsException;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.redisson.api.RAtomicLong;\nimport org.redisson.api.RedissonClient;\n\nimport java.util.concurrent.TimeUnit;\n\n\/**\n * @Description\uff1a\u5bc6\u7801\u91cd\u8bd5\u6bd4\u8f83\u5668\n *\/\npublic class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher {\n\n    private RedissonClient redissonClient;\n\n    private static Long RETRY_LIMIT_NUM = 4L;\n\n    \/**\n     * @Description \u6784\u9020\u51fd\u6570\n     * @param hashAlgorithmName \u5339\u914d\u6b21\u6570\n     * @return\n     *\/\n    public RetryLimitCredentialsMatcher(String hashAlgorithmName,RedissonClient redissonClient) {\n        super(hashAlgorithmName);\n        this.redissonClient = redissonClient;\n    }\n\n    @Override\n    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {\n        \/\/\u83b7\u5f97\u767b\u5f55\u5417\n        String loginName = (String) token.getPrincipal();\n        \/\/\u83b7\u5f97\u7f13\u5b58\n        RAtomicLong atomicLong = redissonClient.getAtomicLong(loginName);\n        long retryFlag = atomicLong.get();\n        \/\/\u5224\u65ad\u6b21\u6570\n        if (retryFlag&gt;RETRY_LIMIT_NUM){\n            \/\/\u8d85\u8fc7\u6b21\u6570\u8bbe\u8ba110\u5206\u949f\u540e\u91cd\u8bd5\n            atomicLong.expire(10, TimeUnit.MICROSECONDS);\n            throw new ExcessiveAttemptsException(\"\u5bc6\u7801\u9519\u8bef5\u6b21\uff0c\u8bf710\u5206\u949f\u4ee5\u540e\u518d\u8bd5\");\n        }\n        \/\/\u7d2f\u52a0\u6b21\u6570\n        atomicLong.incrementAndGet();\n        atomicLong.expire(10, TimeUnit.MICROSECONDS);\n        \/\/\u5bc6\u7801\u6821\u9a8c\n        boolean flag =  super.doCredentialsMatch(token, info);\n        if (flag){\n            \/\/\u6821\u9a8c\u6210\u529f\u5220\u9664\u9650\u5236\n            atomicLong.delete();\n        }\n        return flag;\n    }\n\n\n}\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u91cd\u5199ShiroDbRealmImpl<\/h4>\n<p>\u4fee\u6539initCredentialsMatcher\u65b9\u6cd5\uff0c\u4f7f\u7528RetryLimitCredentialsMatcher<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.constant.SuperConstant;\nimport com.itheima.shiro.core.SimpleCacheManager;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleToken;\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.utils.*;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.subject.PrincipalCollection;\nimport org.apache.shiro.util.ByteSource;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.annotation.Resource;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49shiro\u7684\u5b9e\u73b0\n *\/\npublic class ShiroDbRealmImpl extends ShiroDbRealm {\n\n    @Autowired\n    private UserBridgeService userBridgeService;\n\n    @Autowired\n    private SimpleCacheManager simpleCacheManager;\n\n    @Resource(name = \"redissonClientForShiro\")\n    private RedissonClient redissonClient;\n\n\n    \/**\n     * @Description \u8ba4\u8bc1\u65b9\u6cd5\n     * @param authcToken \u6821\u9a8c\u4f20\u5165\u4ee4\u724c\n     * @return AuthenticationInfo\n     *\/\n    @Override\n    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {\n        SimpleToken token = (SimpleToken)authcToken;\n        User user  = userBridgeService.findUserByLoginName(token.getUsername());\n        if(EmptyUtil.isNullOrEmpty(user)){\n            throw new UnknownAccountException(\"\u8d26\u53f7\u4e0d\u5b58\u5728\");\n        }\n        ShiroUser shiroUser = BeanConv.toBean(user, ShiroUser.class);\n        String sessionId = ShiroUserUtil.getShiroSessionId();\n        String cacheKeyResourcesIds = CacheConstant.RESOURCES_KEY_IDS+sessionId;\n        shiroUser.setResourceIds(userBridgeService.findResourcesIdsList(cacheKeyResourcesIds,user.getId()));\n        String salt = user.getSalt();\n        String password = user.getPassWord();\n        return new SimpleAuthenticationInfo(shiroUser, password, ByteSource.Util.bytes(salt), getName());\n    }\n\n    \/**\n     * @Description \u6388\u6743\u65b9\u6cd5\n     * @param principals SimpleAuthenticationInfo\u5bf9\u8c61\u7b2c\u4e00\u4e2a\u53c2\u6570\n     * @return\n     *\/\n    @Override\n    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();\n        return userBridgeService.getAuthorizationInfo(shiroUser);\n    }\n\n    \/**\n     * @Description \u6e05\u7406\u7f13\u5b58\n     *\/\n    @Override\n    public void doClearCache(PrincipalCollection principalcollection) {\n        String sessionId = ShiroUtil.getShiroSessionId();\n        simpleCacheManager.removeCache(CacheConstant.ROLE_KEY+sessionId);\n        simpleCacheManager.removeCache(CacheConstant.RESOURCES_KEY+sessionId);\n        simpleCacheManager.removeCache(CacheConstant.TOKEN+sessionId);\n    }\n\n    \/**\n     * @Description \u52a0\u5bc6\u65b9\u5f0f\n     *\/\n    @Override\n    public void initCredentialsMatcher() {\n        RetryLimitCredentialsMatcher matcher = new RetryLimitCredentialsMatcher(SuperConstant.HASH_ALGORITHM,redissonClient);\n        matcher.setHashIterations(SuperConstant.HASH_INTERATIONS);\n        setCredentialsMatcher(matcher);\n\n    }\n}\n\n\n<\/code><\/pre>\n<h3>3\u3001\u6d4b\u8bd5<\/h3>\n<p>\u8bbf\u95eehttp:\/\/127.0.0.1\/shiro\/login\uff0c\u4f7f\u7528admin\u8d26\u53f7\u8f93\u5165\u9519\u8bef\u5bc6\u78015\u6b21<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581933402187.png\" alt=\"1581933402187\" \/><\/p>\n<h2>\u7b2c\u4e5d\u7ae0 \u5728\u7ebf\u5e76\u53d1\u767b\u5f55\u4eba\u6570\u63a7\u5236<\/h2>\n<h3>1\u3001\u5b9e\u73b0\u539f\u7406<\/h3>\n<p>\u5728\u5b9e\u9645\u5f00\u53d1\u4e2d\uff0c\u6211\u4eec\u53ef\u80fd\u4f1a\u9047\u5230\u8fd9\u6837\u7684\u9700\u6c42\uff0c\u4e00\u4e2a\u8d26\u53f7\u53ea\u5141\u8bb8\u540c\u65f6\u4e00\u4e2a\u5728\u7ebf\uff0c\u5f53\u8d26\u53f7\u5728\u5176\u4ed6\u5730\u65b9\u767b\u9646\u7684\u65f6\u5019\uff0c\u4f1a\u8e22\u51fa\u524d\u9762\u767b\u9646\u7684\u8d26\u53f7\uff0c\u90a3\u6211\u4eec\u600e\u4e48\u5b9e\u73b0<\/p>\n<ul>\n<li>\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668:\u7ee7\u627fAccessControlFilter<\/p>\n<\/li>\n<li>\n<p>\u4f7f\u7528redis\u961f\u5217\u63a7\u5236\u8d26\u53f7\u5728\u7ebf\u6570\u76ee<\/p>\n<p>\u5b9e\u73b0\u6b65\u9aa4\uff1a<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"language-properties line-numbers\">1\u3001\u53ea\u9488\u5bf9\u767b\u5f55\u7528\u6237\u5904\u7406\uff0c\u9996\u5148\u5224\u65ad\u662f\u5426\u767b\u5f55\n2\u3001\u4f7f\u7528RedissionClien\u521b\u5efa\u961f\u5217\n3\u3001\u5224\u65ad\u5f53\u524dsessionId\u662f\u5426\u5b58\u5728\u4e8e\u6b64\u7528\u6237\u7684\u961f\u5217=key:\u767b\u5f55\u540d value\uff1a\u591a\u4e2asessionId\n4\u3001\u4e0d\u5b58\u5728\u5219\u653e\u5165\u961f\u5217\u5c3e\u7aef==&gt;\u5b58\u5165sessionId\n5\u3001\u5224\u65ad\u5f53\u524d\u961f\u5217\u5927\u5c0f\u662f\u5426\u8d85\u8fc7\u9650\u5b9a\u6b64\u8d26\u53f7\u7684\u53ef\u5728\u7ebf\u4eba\u6570\n6\u3001\u8d85\u8fc7\uff1a\n    *\u4ece\u961f\u5217\u5934\u90e8\u62ff\u5230\u7528\u6237sessionId\n    *\u4ecesessionManger\u6839\u636esessionId\u62ff\u5230session\n    *\u4ecesessionDao\u4e2d\u79fb\u9664session\u4f1a\u8bdd\n7\u3001\u672a\u8d85\u8fc7\uff1a\u653e\u8fc7\u64cd\u4f5c\n\n<\/code><\/pre>\n<h3>2\u3001\u4ee3\u7801\u5b9e\u73b0<\/h3>\n<h4>\u30101\u3011KickedOutAuthorizationFilter<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.filter;\n\nimport com.itheima.shiro.core.impl.RedisSessionDao;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.utils.ShiroUserUtil;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.session.ExpiredSessionException;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.session.UnknownSessionException;\nimport org.apache.shiro.session.mgt.DefaultSessionKey;\nimport org.apache.shiro.session.mgt.eis.SessionDAO;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.web.filter.AccessControlFilter;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.redisson.api.RDeque;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\n\/**\n * @Description\uff1a\n *\/\n@Log4j2\npublic class KickedOutAuthorizationFilter extends AccessControlFilter {\n\n    private RedissonClient redissonClient;\n\n    private SessionDAO redisSessionDao;\n\n    private DefaultWebSessionManager sessionManager;\n\n    public KickedOutAuthorizationFilter(RedissonClient redissonClient, SessionDAO redisSessionDao, DefaultWebSessionManager sessionManager) {\n        this.redissonClient = redissonClient;\n        this.redisSessionDao = redisSessionDao;\n        this.sessionManager = sessionManager;\n    }\n\n    @Override\n    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {\n        return false;\n    }\n\n    @Override\n    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {\n        Subject subject = getSubject(servletRequest, servletResponse);\n        if (!subject.isAuthenticated()) {\n            \/\/\u5982\u679c\u6ca1\u6709\u767b\u5f55\uff0c\u76f4\u63a5\u8fdb\u884c\u4e4b\u540e\u7684\u6d41\u7a0b\n            return true;\n        }\n        \/\/\u5b58\u653esession\u5bf9\u8c61\u8fdb\u5165\u961f\u5217\n        String sessionId = ShiroUserUtil.getShiroSessionId();\n        String LoginName = ShiroUserUtil.getShiroUser().getLoginName();\n        RDeque&lt;String&gt; queue = redissonClient.getDeque(\"KickedOutAuthorizationFilter:\"+LoginName);\n        \/\/\u5224\u65adsessionId\u662f\u5426\u5b58\u5728\u4e8e\u6b64\u7528\u6237\u7684\u961f\u5217\u4e2d\n        boolean flag = queue.contains(sessionId);\n        if (!flag) {\n            queue.addLast(sessionId);\n        }\n        \/\/\u5982\u679c\u6b64\u65f6\u961f\u5217\u5927\u4e8e1\uff0c\u5219\u5f00\u59cb\u8e22\u4eba\n        if (queue.size() &gt; 1) {\n            sessionId = queue.getFirst();\n            queue.removeFirst();\n            Session session = null;\n            try {\n                session = sessionManager.getSession(new DefaultSessionKey(sessionId));\n            }catch (UnknownSessionException ex){\n                log.info(\"session\u5df2\u7ecf\u5931\u6548\");\n            }catch (ExpiredSessionException expiredSessionException){\n                log.info(\"session\u5df2\u7ecf\u8fc7\u671f\");\n            }\n            if (!EmptyUtil.isNullOrEmpty(session)){\n                redisSessionDao.delete(session);\n            }\n        }\n        return true;\n    }\n}\n\n\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u4fee\u6539ShiroConfig<\/h4>\n<pre><code class=\"language-java line-numbers\">\/**\n  * @Description \u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u5b9a\u4e49\n  *\/\nprivate Map&lt;String, Filter&gt; filters() {\n    Map&lt;String, Filter&gt; map = new HashMap&lt;String, Filter&gt;();\n    map.put(\"roleOr\", new RolesOrAuthorizationFilter());\n    map.put(\"kickedOut\", new KickedOutAuthorizationFilter(redissonClient(), redisSessionDao(), shiroSessionManager()));\n    return map;\n}\n\n<\/code><\/pre>\n<h4>\u30103\u3011\u4fee\u6539authentication.properties<\/h4>\n<pre><code class=\"language-properties line-numbers\">#\u9759\u6001\u8d44\u6e90\u4e0d\u8fc7\u6ee4\n\/static\/**=anon\n#\u767b\u5f55\u94fe\u63a5\u4e0d\u8fc7\u6ee4\n\/login\/**=anon\n#\u8bbf\u95ee\/resource\/**\u9700\u8981\u6709admin\u7684\u89d2\u8272\n\/resource\/**=role-or[MangerRole,SuperAdmin]\n#\u5176\u4ed6\u94fe\u63a5\u662f\u9700\u8981\u767b\u5f55\u7684\n\/**=kickedOut,auth\n\n<\/code><\/pre>\n<h3>3\u3001\u6d4b\u8bd5<\/h3>\n<p>\u4f7f\u7528\u8c37\u6b4c\u8bbf\u95eehttp:\/\/127.0.0.1\/shiro\/login\uff0c\u4f7f\u7528admin\/pass\u767b\u9646<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581948184529.png\" alt=\"1581948184529\" \/><\/p>\n<p>\u4f7f\u7528IE\u518d\u8bbf\u95eehttp:\/\/127.0.0.1\/shiro\/login\uff0c\u4f7f\u7528admin\/pass\u767b\u9646<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581948255302.png\" alt=\"1581948255302\" \/><\/p>\n<p>\u518d\u5237\u65b0\u8c37\u6b4c\u6d4f\u89c8\u5668,\u53d1\u73b0\u8d26\u53f7\u88ab\u8e22\u51fa<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581948283827.png\" alt=\"1581948283827\" \/><\/p>\n<h2>\u7b2c\u5341\u7ae0 Springboot+Shiro+Jwt\u524d\u540e\u7aef\u5206\u79bb\u9274\u6743<\/h2>\n<h3>1\u3001\u524d\u540e\u7aef\u5206\u79bb\u4f1a\u8bdd\u95ee\u9898<\/h3>\n<h4>\u30101\u3011\u95ee\u9898\u8ffd\u8e2a<\/h4>\n<p>\u200b       \u524d\u9762\u6211\u4eec\u5b9e\u73b0\u5206\u5e03\u5f0f\u7684\u4f1a\u8bdd\u7f13\u5b58\uff0c\u4f46\u662f\u6211\u4eec\u53d1\u73b0\u6b64\u529f\u80fd\u7684\u5b9e\u73b0\u662f\u57fa\u4e8e\u6d4f\u89c8\u7684cookie\u673a\u5236\uff0c\u4e5f\u5c31\u662f\u8bf4\u7528\u6237\u7981\u7528cookie\u540e\uff0c\u6211\u4eec\u7684\u7cfb\u7edf\u4f1a\u5c31\u4f1a\u4ea7\u751f\u4f1a\u8bdd\u4e0d\u540c\u7684\u95ee\u9898<\/p>\n<h4>\u30102\u3011\u89e3\u51b3\u65b9\u6848<\/h4>\n<p>\u200b      \u6211\u4eec\u7684\u524d\u7aef\u53ef\u80fd\u662fweb\u3001Android\u3001ios\u7b49\u5e94\u7528\uff0c\u540c\u65f6\u6211\u4eec\u6bcf\u4e00\u4e2a\u63a5\u53e3\u90fd\u63d0\u4f9b\u4e86\u65e0\u72b6\u6001\u7684\u5e94\u7b54\u65b9\u5f0f\uff0c\u8fd9\u91cc\u6211\u4eec\u63d0\u4f9b\u4e86\u57fa\u4e8eJWT\u7684token\u751f\u6210\u65b9\u6848<\/p>\n<pre><code class=\"language-properties line-numbers\">1\u3001\u7528\u6237\u767b\u9646\u4e4b\u540e\uff0c\u83b7\u5f97\u6b64\u65f6\u4f1a\u8bdd\u7684sessionId,\u4f7f\u7528JWT\u6839\u636esessionId\u9881\u53d1\u7b7e\u540d\u5e76\u8bbe\u7f6e\u8fc7\u671f\u65f6\u95f4(\u4e0esession\u8fc7\u671f\u65f6\u95f4\u76f8\u540c)\u8fd4\u56detoken\n\n2\u3001\u5c06token\u4fdd\u5b58\u5230\u5ba2\u6237\u7aef\u672c\u5730\uff0c\u5e76\u4e14\u6bcf\u6b21\u53d1\u9001\u8bf7\u6c42\u65f6\u90fd\u5728header\u4e0a\u643a\u5e26JwtToken\n\n3\u3001ShiroSessionManager\u7ee7\u627fDefaultWebSessionManager\uff0c\u91cd\u5199getSessionId\u65b9\u6cd5\uff0c\u4eceheader\u4e0a\u68c0\u6d4b\u662f\u5426\u643a\u5e26JwtToken\uff0c\u5982\u679c\u643a\u5e26\uff0c\u5219\u8fdb\u884c\u89e3\u7801JwtToken\uff0c\u4f7f\u7528JwtToken\u4e2d\u7684jti\u4f5c\u4e3aSessionId\u3002\n\n4\u3001\u91cd\u5199shiro\u7684\u9ed8\u8ba4\u8fc7\u6ee4\u5668\uff0c\u4f7f\u5176\u652f\u6301jwtToken\u6709\u6548\u671f\u6821\u9a8c\u3001\u53ca\u5bf9JSON\u7684\u8fd4\u56de\u652f\u6301\n    JwtAuthcFilter:\u5b9e\u73b0\u662f\u5426\u9700\u8981\u767b\u5f55\u7684\u8fc7\u6ee4\uff0c\u62d2\u7edd\u65f6\u5982\u679cheader\u4e0a\u643a\u5e26JwtToken,\u5219\u8fd4\u56de\u5bf9\u5e94json\n    JwtPermsFilter:\u5b9e\u73b0\u662f\u5426\u6709\u5bf9\u5e94\u8d44\u6e90\u7684\u8fc7\u6ee4\uff0c\u62d2\u7edd\u65f6\u5982\u679cheader\u4e0a\u643a\u5e26JwtToken,\u5219\u8fd4\u56de\u5bf9\u5e94json\n    JwtRolesFilter:\u5b9e\u73b0\u662f\u5426\u6709\u5bf9\u5e94\u89d2\u8272\u7684\u8fc7\u6ee4\uff0c\u62d2\u7edd\u65f6\u5982\u679cheader\u4e0a\u643a\u5e26JwtToken,\u5219\u8fd4\u56de\u5bf9\u5e94json\n\n<\/code><\/pre>\n<h3>2\u3001JWT\u6982\u8ff0<\/h3>\n<p>JWT\uff08JSON WEB TOKEN\uff09\uff1aJSON\u7f51\u7edc\u4ee4\u724c\uff0cJWT\u662f\u4e00\u4e2a\u8f7b\u4fbf\u7684\u5b89\u5168\u8de8\u5e73\u53f0\u4f20\u8f93\u683c\u5f0f\uff0c\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7d27\u51d1\u7684\u81ea\u5305\u542b\u7684\u65b9\u5f0f\u5728\u4e0d\u540c\u5b9e\u4f53\u4e4b\u95f4\u5b89\u5168\u4f20\u8f93\u4fe1\u606f\uff08JSON\u683c\u5f0f\uff09\u3002\u5b83\u662f\u5728Web\u73af\u5883\u4e0b\u4e24\u4e2a\u5b9e\u4f53\u4e4b\u95f4\u4f20\u8f93\u6570\u636e\u7684\u4e00\u9879\u6807\u51c6\u3002\u5b9e\u9645\u4e0a\u4f20\u8f93\u7684\u5c31\u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\u3002<\/p>\n<ul>\n<li>\u5e7f\u4e49\u4e0a\uff1aJWT\u662f\u4e00\u4e2a\u6807\u51c6\u7684\u540d\u79f0\uff1b<\/p>\n<\/li>\n<li>\n<p>\u72ed\u4e49\u4e0a\uff1aJWT\u6307\u7684\u5c31\u662f\u7528\u6765\u4f20\u9012\u7684\u90a3\u4e2atoken\u5b57\u7b26\u4e32<\/p>\n<\/li>\n<\/ul>\n<p>JWT\u7531\u4e09\u90e8\u5206\u6784\u6210\uff1aheader\uff08\u5934\u90e8\uff09\u3001payload\uff08\u8f7d\u8377\uff09\u548csignature\uff08\u7b7e\u540d\uff09\u3002<\/p>\n<ol>\n<li>Header\n<p>\u5b58\u50a8\u4e24\u4e2a\u53d8\u91cf<\/p>\n<ol>\n<li>\u79d8\u94a5\uff08\u53ef\u4ee5\u7528\u6765\u6bd4\u5bf9\uff09<\/li>\n<li>\u7b97\u6cd5\uff08\u4e5f\u5c31\u662f\u4e0b\u9762\u5c06Header\u548cpayload\u52a0\u5bc6\u6210Signature\uff09<\/li>\n<\/ol>\n<\/li>\n<li>payload\n<p>\u5b58\u50a8\u5f88\u591a\u4e1c\u897f\uff0c\u57fa\u7840\u4fe1\u606f\u6709\u5982\u4e0b\u51e0\u4e2a<\/p>\n<ol>\n<li>\u7b7e\u53d1\u4eba\uff0c\u4e5f\u5c31\u662f\u8fd9\u4e2a\u201c\u4ee4\u724c\u201d\u5f52\u5c5e\u4e8e\u54ea\u4e2a\u7528\u6237\u3002\u4e00\u822c\u662f<code>userId<\/code><\/li>\n<li>\u521b\u5efa\u65f6\u95f4\uff0c\u4e5f\u5c31\u662f\u8fd9\u4e2a\u4ee4\u724c\u662f\u4ec0\u4e48\u65f6\u5019\u521b\u5efa\u7684<\/li>\n<li>\u5931\u6548\u65f6\u95f4\uff0c\u4e5f\u5c31\u662f\u8fd9\u4e2a\u4ee4\u724c\u4ec0\u4e48\u65f6\u5019\u5931\u6548(session\u7684\u5931\u6548\u65f6\u95f4)<\/li>\n<li>\u552f\u4e00\u6807\u8bc6\uff0c\u4e00\u822c\u53ef\u4ee5\u4f7f\u7528\u7b97\u6cd5\u751f\u6210\u4e00\u4e2a\u552f\u4e00\u6807\u8bc6\uff08jti<span class=\"text-highlighted-inline\" style=\"background-color: #fffd38;\">>sessionId\uff09<\/span><\/li>\n<\/ol>\n<\/li>\n<li>Signature\n<p>\u8fd9\u4e2a\u662f\u4e0a\u9762\u4e24\u4e2a\u7ecf\u8fc7Header\u4e2d\u7684\u7b97\u6cd5\u52a0\u5bc6\u751f\u6210\u7684\uff0c\u7528\u4e8e\u6bd4\u5bf9\u4fe1\u606f\uff0c\u9632\u6b62\u7be1\u6539Header\u548cpayload<\/p>\n<\/li>\n<\/ol>\n<p>\u7136\u540e\u5c06\u8fd9\u4e09\u4e2a\u90e8\u5206\u7684\u4fe1\u606f\u7ecf\u8fc7\u52a0\u5bc6\u751f\u6210\u4e00\u4e2a<code>JwtToken<\/code>\u7684\u5b57\u7b26\u4e32\uff0c\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u4fdd\u5b58\u5728\u672c\u5730\u3002\u5f53\u5ba2\u6237\u7aef\u53d1\u8d77\u8bf7\u6c42\u7684\u65f6\u5019\u643a\u5e26\u8fd9\u4e2a\u5230\u670d\u52a1\u7aef(\u53ef\u4ee5\u662f\u5728<code>cookie<\/code>\uff0c\u53ef\u4ee5\u662f\u5728<code>header<\/code>)\uff0c\u5728\u670d\u52a1\u7aef\u8fdb\u884c\u9a8c\u8bc1\uff0c\u6211\u4eec\u9700\u8981\u89e3\u5bc6\u5bf9\u4e8e\u7684payload\u7684\u5185\u5bb9<\/p>\n<h3>3\u3001\u96c6\u6210JWT<\/h3>\n<h4>\u30101\u3011JwtProperties<\/h4>\n<p>\u200b   \u7528\u4e8e\u652f\u6301yaml\u6587\u4ef6\u914d\u7f6e\u7684\u914d\u7f6e\u7c7b<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\n\n\/**\n * @Description\uff1ajw\u914d\u7f6e\u6587\u4ef6\n *\/\n@Data\n@ConfigurationProperties(prefix = \"itheima.framework.jwt\")\npublic class JwtProperties implements Serializable {\n\n    \/**\n     * @Description \u7b7e\u540d\u5bc6\u7801\n     *\/\n    private String hexEncodedSecretKey;\n}\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011JwtTokenManager<\/h4>\n<p>\u8d1f\u8d23\u4ee4\u724c\u7684\u9881\u53d1\u3001\u89e3\u6790\u3001\u6821\u9a8c<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.auth0.jwt.JWT;\nimport com.auth0.jwt.JWTVerifier;\nimport com.auth0.jwt.algorithms.Algorithm;\nimport com.itheima.shiro.config.JwtProperties;\nimport com.itheima.shiro.utils.EncodesUtil;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.JwtBuilder;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.stereotype.Service;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\n@Service(\"jwtTokenManager\")\n@EnableConfigurationProperties({JwtProperties.class})\npublic class JwtTokenManager {\n\n    @Autowired\n    JwtProperties jwtProperties;\n\n\n    \/**\n     * @Description \u7b7e\u53d1\u4ee4\u724c\n     *      jwt\u5b57\u7b26\u4e32\u5305\u62ec\u4e09\u4e2a\u90e8\u5206\n     *        1. header\n     *            -\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u7c7b\u578b\uff0c\u4e00\u822c\u90fd\u662f\u201cJWT\u201d\n     *            -\u54ea\u79cd\u7b97\u6cd5\u52a0\u5bc6\uff0c\u201cHS256\u201d\u6216\u8005\u5176\u4ed6\u7684\u52a0\u5bc6\u7b97\u6cd5\n     *            \u6240\u4ee5\u4e00\u822c\u90fd\u662f\u56fa\u5b9a\u7684\uff0c\u6ca1\u6709\u4ec0\u4e48\u53d8\u5316\n     *        2. payload\n     *            \u4e00\u822c\u6709\u56db\u4e2a\u6700\u5e38\u89c1\u7684\u6807\u51c6\u5b57\u6bb5\uff08\u4e0b\u9762\u6709\uff09\n     *            iat\uff1a\u7b7e\u53d1\u65f6\u95f4\uff0c\u4e5f\u5c31\u662f\u8fd9\u4e2ajwt\u4ec0\u4e48\u65f6\u5019\u751f\u6210\u7684\n     *            jti\uff1aJWT\u7684\u552f\u4e00\u6807\u8bc6\n     *            iss\uff1a\u7b7e\u53d1\u4eba\uff0c\u4e00\u822c\u90fd\u662fusername\u6216\u8005userId\n     *            exp\uff1a\u8fc7\u671f\u65f6\u95f4\n     * @param iss \u7b7e\u53d1\u4eba\n     * @param ttlMillis \u6709\u6548\u65f6\u95f4\n     * @param claims jwt\u4e2d\u5b58\u50a8\u7684\u4e00\u4e9b\u975e\u9690\u79c1\u4fe1\u606f\n     * @return\n     *\/\n    public String IssuedToken(String iss, long ttlMillis,String sessionId, Map&lt;String, Object&gt; claims) {\n        if (claims == null) {\n            claims = new HashMap&lt;&gt;();\n        }\n        long nowMillis = System.currentTimeMillis();\n\n        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtProperties.getBase64EncodedSecretKey().getBytes());\n\n        JwtBuilder builder = Jwts.builder()\n                .setClaims(claims)\n                .setId(sessionId)\/\/2. \u8fd9\u4e2a\u662fJWT\u7684\u552f\u4e00\u6807\u8bc6\uff0c\u4e00\u822c\u8bbe\u7f6e\u6210\u552f\u4e00\u7684\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u751f\u6210\u552f\u4e00\u6807\u8bc6,\u6b64\u65f6\u5b58\u50a8\u7684\u4e3asessionId,\u767b\u5f55\u6210\u529f\u540e\u56de\u5199\n                .setIssuedAt(new Date(nowMillis))\/\/1. \u8fd9\u4e2a\u5730\u65b9\u5c31\u662f\u4ee5\u6beb\u79d2\u4e3a\u5355\u4f4d\uff0c\u6362\u7b97\u5f53\u524d\u7cfb\u7edf\u65f6\u95f4\u751f\u6210\u7684iat\n                .setSubject(iss)\/\/3. \u7b7e\u53d1\u4eba\uff0c\u4e5f\u5c31\u662fJWT\u662f\u7ed9\u8c01\u7684\uff08\u903b\u8f91\u4e0a\u4e00\u822c\u90fd\u662fusername\u6216\u8005userId\uff09\n                .signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey);\/\/\u8fd9\u4e2a\u5730\u65b9\u662f\u751f\u6210jwt\u4f7f\u7528\u7684\u7b97\u6cd5\u548c\u79d8\u94a5\n        if (ttlMillis &gt;= 0) {\n            long expMillis = nowMillis + ttlMillis;\n            Date exp = new Date(expMillis);\/\/4. \u8fc7\u671f\u65f6\u95f4\uff0c\u8fd9\u4e2a\u4e5f\u662f\u4f7f\u7528\u6beb\u79d2\u751f\u6210\u7684\uff0c\u4f7f\u7528\u5f53\u524d\u65f6\u95f4+\u524d\u9762\u4f20\u5165\u7684\u6301\u7eed\u65f6\u95f4\u751f\u6210\n            builder.setExpiration(exp);\n        }\n        return builder.compact();\n    }\n\n    \/**\n     * @Description \u89e3\u6790\u4ee4\u724c\n     * @param jwtToken \u4ee4\u724c\n     * @return\n     *\/\n    public Claims decodeToken(String jwtToken) {\n\n        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtProperties.getBase64EncodedSecretKey().getBytes());\n\n        \/\/ \u5f97\u5230 DefaultJwtParser\n        return Jwts.parser()\n                \/\/ \u8bbe\u7f6e\u7b7e\u540d\u7684\u79d8\u94a5\n                .setSigningKey(base64EncodedSecretKey)\n                \/\/ \u8bbe\u7f6e\u9700\u8981\u89e3\u6790\u7684 jwt\n                .parseClaimsJws(jwtToken)\n                .getBody();\n    }\n\n    \/**\n     * @Description \u5224\u65ad\u4ee4\u724c\u662f\u5426\u5408\u6cd5\n     * @param jwtToken \u4ee4\u724c\n     * @return\n     *\/\n    public boolean isVerifyToken(String jwtToken) {\n\n        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtProperties.getBase64EncodedSecretKey().getBytes());\n\n        \/\/\u8fd9\u4e2a\u662f\u5b98\u65b9\u7684\u6821\u9a8c\u89c4\u5219\uff0c\u8fd9\u91cc\u53ea\u5199\u4e86\u4e00\u4e2a\u201d\u6821\u9a8c\u7b97\u6cd5\u201c\uff0c\u53ef\u4ee5\u81ea\u5df1\u52a0\n        Algorithm algorithm = Algorithm.HMAC256(EncodesUtil.decodeBase64(base64EncodedSecretKey));\n        JWTVerifier verifier = JWT.require(algorithm).build();\n        verifier.verify(jwtToken);  \/\/ \u6821\u9a8c\u4e0d\u901a\u8fc7\u4f1a\u629b\u51fa\u5f02\u5e38\n        \/\/\u5224\u65ad\u5408\u6cd5\u7684\u6807\u51c6\uff1a1. \u5934\u90e8\u548c\u8377\u8f7d\u90e8\u5206\u6ca1\u6709\u7be1\u6539\u8fc7\u30022. \u6ca1\u6709\u8fc7\u671f\n        return true;\n    }\n\n}\n\n<\/code><\/pre>\n<h3>4\u3001\u91cd\u5199DefaultWebSessionManager<\/h3>\n<p>ShiroSessionManager\u4e3b\u8981\u662f\u6dfb\u52a0jwtToken\u7684jti\u4f5c\u4e3a\u4f1a\u8bdd\u7684\u552f\u4e00\u6807\u8bc6<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.utils.EmptyUtil;\nimport io.jsonwebtoken.Claims;\nimport org.apache.shiro.web.servlet.ShiroHttpServletRequest;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.apache.shiro.web.util.WebUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.Serializable;\n\n\/**\n * @Description \u91cd\u5199Jwt\u4f1a\u8bdd\u7ba1\u7406\n *\/\n\npublic class ShiroSessionManager extends DefaultWebSessionManager {\n\n    private static final String AUTHORIZATION = \"jwtToken\";\n\n    private static final String REFERENCED_SESSION_ID_SOURCE = \"Stateless request\";\n\n    public ShiroSessionManager(){\n        super();\n    }\n\n    @Autowired\n    JwtTokenManager jwtTokenManager;\n\n    @Override\n    protected Serializable getSessionId(ServletRequest request, ServletResponse response){\n        String jwtToken = WebUtils.toHttp(request).getHeader(AUTHORIZATION);\n        if(EmptyUtil.isNullOrEmpty(jwtToken)){\n            \/\/\u5982\u679c\u6ca1\u6709\u643a\u5e26id\u53c2\u6570\u5219\u6309\u7167\u7236\u7c7b\u7684\u65b9\u5f0f\u5728cookie\u8fdb\u884c\u83b7\u53d6\n            return super.getSessionId(request, response);\n        }else{\n            \/\/\u5982\u679c\u8bf7\u6c42\u5934\u4e2d\u6709 authToken \u5219\u5176\u503c\u4e3ajwtToken\uff0c\u7136\u540e\u89e3\u6790\u51fa\u4f1a\u8bddsession\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);\n            Claims decode = jwtTokenManager.decodeToken(jwtToken);\n            String id = (String) decode.get(\"jti\");\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);\n            return id;\n        }\n    }\n\n}\n\n\n<\/code><\/pre>\n<h3>5\u3001\u91cd\u5199\u9ed8\u8ba4\u8fc7\u6ee4\u5668<\/h3>\n<p>BaseResponse\u8fd4\u56de\u7edf\u4e00json\u7684\u5bf9\u8c61<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.base;\n\nimport com.itheima.shiro.utils.ToString;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\n\n\/**\n * @Description \u57fa\u7840\u8fd4\u56de\u5c01\u88c5\n *\/\n@Data\npublic class BaseResponse extends ToString {\n    private Integer code ;\n\n    private String msg ;\n\n    private String date;\n\n    private static final long serialVersionUID = -1;\n\n    public BaseResponse(Integer code, String msg) {\n        this.code = code;\n        this.msg = msg;\n    }\n\n    public BaseResponse(Integer code, String msg, String date) {\n        this.code = code;\n        this.msg = msg;\n        this.date = date;\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30101\u3011JwtAuthcFilter<\/h4>\n<p>\u4f7f\u7528wtTokenManager.isVerifyToken(jwtToken)\u6821\u9a8c\u9881\u53d1jwtToken\u662f\u5426\u5408\u6cd5\uff0c\u540c\u65f6\u5728\u62d2\u7edd\u7684\u65f6\u5019\u8fd4\u56de\u5bf9\u5e94\u7684json\u6570\u636e\u683c\u5f0f<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.filter;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.itheima.shiro.constant.ShiroConstant;\nimport com.itheima.shiro.core.base.BaseResponse;\nimport com.itheima.shiro.core.impl.JwtTokenManager;\nimport com.itheima.shiro.core.impl.ShiroSessionManager;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport org.apache.shiro.web.filter.authc.FormAuthenticationFilter;\nimport org.apache.shiro.web.util.WebUtils;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49\u767b\u5f55\u9a8c\u8bc1\u8fc7\u6ee4\u5668\n *\/\npublic class JwtAuthcFilter extends FormAuthenticationFilter {\n\n    private JwtTokenManager jwtTokenManager;\n\n    public JwtAuthcFilter(JwtTokenManager jwtTokenManager) {\n        this.jwtTokenManager = jwtTokenManager;\n    }\n\n    \/**\n     * @Description \u662f\u5426\u5141\u8bb8\u8bbf\u95ee\n     *\/\n    @Override\n    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {\n        \/\/\u5224\u65ad\u5f53\u524d\u8bf7\u6c42\u5934\u4e2d\u662f\u5426\u5e26\u6709jwtToken\u7684\u5b57\u7b26\u4e32\n        String jwtToken = WebUtils.toHttp(request).getHeader(\"jwtToken\");\n        \/\/\u5982\u679c\u6709\uff1a\u8d70jwt\u6821\u9a8c\n        if (!EmptyUtil.isNullOrEmpty(jwtToken)){\n            boolean verifyToken = jwtTokenManager.isVerifyToken(jwtToken);\n            if (verifyToken){\n                return super.isAccessAllowed(request, response, mappedValue);\n            }else {\n                return false;\n            }\n        }\n        \/\/\u6ca1\u6709\u6ca1\u6709\uff1a\u8d70\u539f\u59cb\u6821\u9a8c\n        return super.isAccessAllowed(request, response, mappedValue);\n    }\n\n    \/**\n     * @Description \u8bbf\u95ee\u62d2\u7edd\u65f6\u8c03\u7528\n     *\/\n    @Override\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {\n        \/\/\u5224\u65ad\u5f53\u524d\u8bf7\u6c42\u5934\u4e2d\u662f\u5426\u5e26\u6709jwtToken\u7684\u5b57\u7b26\u4e32\n        String jwtToken = WebUtils.toHttp(request).getHeader(\"jwtToken\");\n        \/\/\u5982\u679c\u6709\uff1a\u8fd4\u56dejson\u7684\u5e94\u7b54\n        if (!EmptyUtil.isNullOrEmpty(jwtToken)){\n            BaseResponse baseResponse = new BaseResponse(ShiroConstant.NO_LOGIN_CODE,ShiroConstant.NO_LOGIN_MESSAGE);\n            response.setCharacterEncoding(\"UTF-8\");\n            response.setContentType(\"application\/json; charset=utf-8\");\n            response.getWriter().write(JSONObject.toJSONString(baseResponse));\n            return false;\n        }\n        \/\/\u5982\u679c\u6ca1\u6709\uff1a\u8d70\u539f\u59cb\u65b9\u5f0f\n        return super.onAccessDenied(request, response);\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011JwtPermsFilter<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.filter;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.itheima.shiro.constant.ShiroConstant;\nimport com.itheima.shiro.core.base.BaseResponse;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;\nimport org.apache.shiro.web.util.WebUtils;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49jwt\u7684\u8d44\u6e90\u6821\u9a8c\n *\/\npublic class JwtPermsFilter extends PermissionsAuthorizationFilter {\n\n    \/**\n     * @Description \u8bbf\u95ee\u62d2\u7edd\u65f6\u8c03\u7528\n     *\/\n    @Override\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {\n        \/\/\u5224\u65ad\u5f53\u524d\u8bf7\u6c42\u5934\u4e2d\u662f\u5426\u5e26\u6709jwtToken\u7684\u5b57\u7b26\u4e32\n        String jwtToken = WebUtils.toHttp(request).getHeader(\"jwtToken\");\n        \/\/\u5982\u679c\u6709\uff1a\u8fd4\u56dejson\u7684\u5e94\u7b54\n        if (!EmptyUtil.isNullOrEmpty(jwtToken)){\n            BaseResponse baseResponse = new BaseResponse(ShiroConstant.NO_AUTH_CODE,ShiroConstant.NO_AUTH_MESSAGE);\n            response.setCharacterEncoding(\"UTF-8\");\n            response.setContentType(\"application\/json; charset=utf-8\");\n            response.getWriter().write(JSONObject.toJSONString(baseResponse));\n            return false;\n        }\n        \/\/\u5982\u679c\u6ca1\u6709\uff1a\u8d70\u539f\u59cb\u65b9\u5f0f\n        return super.onAccessDenied(request, response);\n    }\n}\n\n\n<\/code><\/pre>\n<h4>\u30103\u3011JwtRolesFilter<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.filter;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.itheima.shiro.constant.ShiroConstant;\nimport com.itheima.shiro.core.base.BaseResponse;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;\nimport org.apache.shiro.web.util.WebUtils;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.IOException;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49jwt\u89d2\u8272\u6821\u9a8c\n *\/\npublic class JwtRolesFilter extends RolesAuthorizationFilter {\n\n    \/**\n     * @Description \u8bbf\u95ee\u62d2\u7edd\u65f6\u8c03\u7528\n     *\/\n    @Override\n    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {\n        \/\/\u5224\u65ad\u5f53\u524d\u8bf7\u6c42\u5934\u4e2d\u662f\u5426\u5e26\u6709jwtToken\u7684\u5b57\u7b26\u4e32\n        String jwtToken = WebUtils.toHttp(request).getHeader(\"jwtToken\");\n        \/\/\u5982\u679c\u6709\uff1a\u8fd4\u56dejson\u7684\u5e94\u7b54\n        if (!EmptyUtil.isNullOrEmpty(jwtToken)){\n            BaseResponse baseResponse = new BaseResponse(ShiroConstant.NO_ROLE_CODE,ShiroConstant.NO_ROLE_MESSAGE);\n            response.setCharacterEncoding(\"UTF-8\");\n            response.setContentType(\"application\/json; charset=utf-8\");\n            response.getWriter().write(JSONObject.toJSONString(baseResponse));\n            return false;\n        }\n        \/\/\u5982\u679c\u6ca1\u6709\uff1a\u8d70\u539f\u59cb\u65b9\u5f0f\n        return super.onAccessDenied(request, response);\n    }\n}\n\n\n<\/code><\/pre>\n<h3>6\u3001\u91cd\u5199ShiroConfig<\/h3>\n<p>1\u3001ShiroSessionManager\u66ff\u6362DefaultWebSessionManager<\/p>\n<p>2\u3001\u751f\u6548\u8fc7\u6ee4\u5668<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\n\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.impl.*;\nimport com.itheima.shiro.filter.*;\nimport com.itheima.shiro.properties.PropertiesUtil;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.session.mgt.eis.SessionDAO;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.redisson.Redisson;\nimport org.redisson.api.RedissonClient;\nimport org.redisson.config.Config;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\nimport javax.servlet.Filter;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description \u6743\u9650\u914d\u7f6e\u7c7b\n *\/\n@Configuration\n@ComponentScan(basePackages = {\"com.itheima.shiro.core\"})\n@EnableConfigurationProperties({ShiroRedisProperties.class})\n@Log4j2\npublic class ShiroConfig {\n\n    @Autowired\n    private ShiroRedisProperties shiroRedisProperties;\n\n    @Autowired\n    JwtTokenManager jwtTokenManager;\n\n    \/**\n     * @Description redission\u5ba2\u6237\u7aef\n     *\/\n    @Bean(\"redissonClientForShiro\")\n    public RedissonClient redissonClient() {\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5f00\u59cb======\");\n        String[] nodeList = shiroRedisProperties.getNodes().split(\",\");\n        Config config = new Config();\n        if (nodeList.length == 1) {\n            config.useSingleServer().setAddress(nodeList[0])\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        } else {\n            config.useClusterServers().addNodeAddress(nodeList)\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        }\n        RedissonClient redissonClient =  Redisson.create(config);\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5b8c\u6210======\");\n        return redissonClient;\n    }\n\n    \/**\n     * @Description \u521b\u5efacookie\u5bf9\u8c61\n     *\/\n    @Bean(name=\"sessionIdCookie\")\n    public SimpleCookie simpleCookie(){\n        SimpleCookie simpleCookie = new SimpleCookie();\n        simpleCookie.setName(\"ShiroSession\");\n        return simpleCookie;\n    }\n\n    \/**\n     * @Description \u7f13\u5b58\u7ba1\u7406\u5668\n     * @param\n     * @return\n     *\/\n    @Bean(name=\"shiroCacheManager\")\n    public ShiroCacheManager shiroCacheManager(){\n        return new ShiroCacheManager();\n    }\n\n    \/**\n     * @Description \u6743\u9650\u7ba1\u7406\u5668\n     * @param\n     * @return\n     *\/\n    @Bean(name=\"securityManager\")\n    public DefaultWebSecurityManager defaultWebSecurityManager(){\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(shiroDbRealm());\n        securityManager.setSessionManager(shiroSessionManager());\n        securityManager.setCacheManager(shiroCacheManager());\n        return securityManager;\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49RealmImpl\n     *\/\n    @Bean(name=\"shiroDbRealm\")\n    public ShiroDbRealm shiroDbRealm(){\n        return new ShiroDbRealmImpl();\n    }\n\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49session\u4f1a\u8bdd\u5b58\u50a8\u7684\u5b9e\u73b0\u7c7b \uff0c\u4f7f\u7528Redis\u6765\u5b58\u50a8\u5171\u4eabsession\uff0c\u8fbe\u5230\u5206\u5e03\u5f0f\u90e8\u7f72\u76ee\u7684\n     *\/\n    @Bean(\"redisSessionDao\")\n    public SessionDAO redisSessionDao(){\n        RedisSessionDao sessionDAO =   new RedisSessionDao();\n        sessionDAO.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());\n        return sessionDAO;\n    }\n\n    \/**\n     * @Description \u4f1a\u8bdd\u7ba1\u7406\u5668\n     *\/\n    @Bean(name=\"sessionManager\")\n    public ShiroSessionManager shiroSessionManager(){\n        ShiroSessionManager sessionManager = new ShiroSessionManager();\n        sessionManager.setSessionDAO(redisSessionDao());\n        sessionManager.setSessionValidationSchedulerEnabled(false);\n        sessionManager.setSessionIdCookieEnabled(true);\n        sessionManager.setSessionIdCookie(simpleCookie());\n        sessionManager.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());\n        return sessionManager;\n    }\n\n    \/**\n     * @Description \u4fdd\u8bc1\u5b9e\u73b0\u4e86Shiro\u5185\u90e8lifecycle\u51fd\u6570\u7684bean\u6267\u884c\n     *\/\n    @Bean(name = \"lifecycleBeanPostProcessor\")\n    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    \/**\n     * @Description AOP\u5f0f\u65b9\u6cd5\u7ea7\u6743\u9650\u68c0\u67e5\n     *\/\n    @Bean\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);\n        return defaultAdvisorAutoProxyCreator;\n    }\n\n    \/**\n     * @Description \u914d\u5408DefaultAdvisorAutoProxyCreator\u4e8b\u9879\u6ce8\u89e3\u6743\u9650\u6821\u9a8c\n     *\/\n    @Bean\n    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {\n        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();\n        aasa.setSecurityManager(defaultWebSecurityManager());\n        return new AuthorizationAttributeSourceAdvisor();\n    }\n\n    \/**\n     * @Description \u8fc7\u6ee4\u5668\u94fe\n     *\/\n    private Map&lt;String, String&gt; filterChainDefinition(){\n        List&lt;Object&gt; list  = PropertiesUtil.propertiesShiro.getKeyList();\n        Map&lt;String, String&gt; map = new LinkedHashMap&lt;&gt;();\n        for (Object object : list) {\n            String key = object.toString();\n            String value = PropertiesUtil.getShiroValue(key);\n            log.info(\"\u8bfb\u53d6\u9632\u6b62\u76d7\u94fe\u63a7\u5236\uff1a---key{},---value:{}\",key,value);\n            map.put(key, value);\n        }\n        return map;\n    }\n\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u5b9a\u4e49\n     *\/\n    private Map&lt;String, Filter&gt; filters() {\n        Map&lt;String, Filter&gt; map = new HashMap&lt;String, Filter&gt;();\n        map.put(\"roleOr\", new RolesOrAuthorizationFilter());\n        map.put(\"kicked-out\", new KickedOutAuthorizationFilter(redissonClient(), redisSessionDao(), shiroSessionManager()));\n        map.put(\"jwt-authc\", new JwtAuthcFilter(jwtTokenManager));\n        map.put(\"jwt-perms\", new JwtPermsFilter());\n        map.put(\"jwt-roles\", new JwtRolesFilter());\n        return map;\n    }\n\n    \/**\n     * @Description Shiro\u8fc7\u6ee4\u5668\n     *\/\n    @Bean(\"shiroFilter\")\n    public ShiroFilterFactoryBean shiroFilterFactoryBean(){\n        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(defaultWebSecurityManager());\n        \/\/\u4f7f\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u751f\u6548\n        shiroFilter.setFilters(filters());\n        shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());\n        shiroFilter.setLoginUrl(\"\/login\");\n        shiroFilter.setUnauthorizedUrl(\"\/login\");\n        return shiroFilter;\n    }\n\n}\n\n\n<\/code><\/pre>\n<h3>7\u3001\u4e1a\u52a1\u4ee3\u7801<\/h3>\n<h4>\u30101\u3011LoginAction<\/h4>\n<p>\u6dfb\u52a0LoginForJwt\u65b9\u6cd5<\/p>\n<pre><code class=\"language-java line-numbers\">\/**\n     * @Description jwt\u7684json\u767b\u5f55\u65b9\u5f0f\n     * @param loginVo\n     * @return\n     *\/\n    @RequestMapping(\"login-jwt\")\n    @ResponseBody\n    public BaseResponse LoginForJwt(@RequestBody LoginVo loginVo){\n        return loginService.routeForJwt(loginVo);\n    }\n\n<\/code><\/pre>\n<h4>\u30102\u3011LoginService<\/h4>\n<p>\u6dfb\u52a0routeForJwt\u65b9\u6cd5<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service;\n\nimport com.itheima.shiro.core.base.BaseResponse;\nimport com.itheima.shiro.vo.LoginVo;\nimport org.apache.shiro.authc.IncorrectCredentialsException;\nimport org.apache.shiro.authc.UnknownAccountException;\n\nimport java.util.Map;\n\n\/**\n * @Description \u767b\u9646\u4e1a\u52a1\u63a5\u53e3\n *\/\n\npublic interface LoginService {\n\n    \/**\n     * @Description \u767b\u9646\u8def\u7531\n     * @param loginVo \u767b\u5f55\u53c2\u6570\n     * @return\n     *\/\n    public Map&lt;String, String&gt; route(LoginVo loginVo) throws UnknownAccountException,IncorrectCredentialsException;\n\n    \/**\n     * @Description jwt\u65b9\u5f0f\u767b\u5f55\n     @param loginVo \u767b\u5f55\u53c2\u6570\n     * @return\n     *\/\n    public BaseResponse routeForJwt(LoginVo loginVo) throws UnknownAccountException,IncorrectCredentialsException;\n\n}\n\n\n\n<\/code><\/pre>\n<h4>\u30103\u3011LoginServiceImpl<\/h4>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.constant.ShiroConstant;\nimport com.itheima.shiro.core.base.BaseResponse;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleToken;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.core.impl.JwtTokenManager;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.service.LoginService;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.ShiroUserUtil;\nimport com.itheima.shiro.utils.ShiroUtil;\nimport com.itheima.shiro.vo.LoginVo;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.IncorrectCredentialsException;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.apache.shiro.subject.Subject;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n\/**\n * @Description \u767b\u9646\u4e1a\u52a1\u5b9e\u73b0\n *\/\n@Service(\"loginService\")\n@Log4j2\npublic class LoginServiceImpl implements LoginService {\n\n    @Resource(name = \"redissonClientForShiro\")\n    RedissonClient redissonClient;\n\n    @Autowired\n    UserBridgeService userBridgeService;\n\n    @Autowired\n    JwtTokenManager jwtTokenManager;\n\n    \/* (non-Javadoc)\n     * @see LoginService#route(com.yz.commons.vo.LoginVo)\n     *\/\n    @Override\n    public Map&lt;String, String&gt; route(LoginVo loginVo) throws UnknownAccountException, IncorrectCredentialsException {\n        Map&lt;String, String&gt; map = new HashMap&lt;&gt;();\n        try {\n            SimpleToken token = new SimpleToken(null, loginVo.getLoginName(), loginVo.getPassWord());\n            Subject subject = SecurityUtils.getSubject();\n            subject.login(token);\n            \/\/\u521b\u5efa\u7f13\u5b58\n            this.loadAuthorityToCache();\n        } catch (UnknownAccountException ex) {\n            log.error(\"\u767b\u9646\u5f02\u5e38:{}\", ex);\n            throw new UnknownAccountException(ex);\n        } catch (IncorrectCredentialsException ex) {\n            log.error(\"\u767b\u9646\u5f02\u5e38:{}\", ex);\n            throw new IncorrectCredentialsException(ex);\n        }\n        return map;\n    }\n\n    @Override\n    public BaseResponse routeForJwt(LoginVo loginVo) throws UnknownAccountException, IncorrectCredentialsException {\n        Map&lt;String, String&gt; map = new HashMap&lt;&gt;();\n        String jwtToken = null;\n        try {\n            SimpleToken token = new SimpleToken(null, loginVo.getLoginName(), loginVo.getPassWord());\n            Subject subject = SecurityUtils.getSubject();\n            subject.login(token);\n            String shiroSessionId = ShiroUserUtil.getShiroSessionId();\n            \/\/\u767b\u5f55\u540e\u9881\u53d1\u7684\u4ee4\u724c\n            ShiroUser shiroUser = ShiroUserUtil.getShiroUser();\n            Map&lt;String, Object&gt; claims = new HashMap&lt;&gt;();\n            claims.put(\"shiroUser\", JSONObject.toJSONString(shiroUser));\n            jwtToken = jwtTokenManager.IssuedToken(\"system\", subject.getSession().getTimeout(),shiroSessionId,claims);\n            map.put(\"jwtToken\",jwtToken );\n            log.info(\"jwtToken:{}\",map.toString());\n            \/\/\u521b\u5efa\u7f13\u5b58\n            this.loadAuthorityToCache();\n        } catch (Exception ex) {\n            BaseResponse baseResponse = new BaseResponse(ShiroConstant.LOGIN_FAILURE_CODE, ShiroConstant.LOGIN_FAILURE_MESSAGE);\n            return baseResponse;\n        }\n        BaseResponse baseResponse = new BaseResponse(ShiroConstant.LOGIN_SUCCESS_CODE,ShiroConstant.LOGIN_SUCCESS_MESSAGE,jwtToken);\n        return baseResponse;\n    }\n\n    \/**\n     *\n     * &lt;b&gt;\u65b9\u6cd5\u540d\uff1a&lt;\/b&gt;\uff1aloadAuthorityToCache&lt;br&gt;\n     * &lt;b&gt;\u529f\u80fd\u8bf4\u660e\uff1a&lt;\/b&gt;\uff1a\u52a0\u8f7d\u7f13\u5b58&lt;br&gt;\n     *\/\n    private void loadAuthorityToCache(){\n        \/\/\u767b\u9646\u6210\u529f\u540e\u7f13\u5b58\u7528\u6237\u7684\u6743\u9650\u4fe1\u606f\u8fdb\u5165\u7f13\u5b58\n        ShiroUser shiroUser = ShiroUserUtil.getShiroUser();\n        User user = BeanConv.toBean(shiroUser, User.class);\n        userBridgeService.loadUserAuthorityToCache(user);\n\n    }\n\n}\n\n\n<\/code><\/pre>\n<p>\u30105\u3011authentication.properties<\/p>\n<pre><code class=\"language-properties line-numbers\">#\u9759\u6001\u8d44\u6e90\u4e0d\u8fc7\u6ee4\n\/static\/**=anon\n#\u767b\u5f55\u94fe\u63a5\u4e0d\u8fc7\u6ee4\n\/login\/**=anon\n#\u8bbf\u95ee\/resource\/**\u9700\u8981\u6709admin\u7684\u89d2\u8272\n#\/resource\/**=roleOr[MangerRole,SuperAdmin]\n\/role\/** =jwt-roles[SuperAdmin]\n\/resource\/** =jwt-perms[role:listInitialize]\n#\u5176\u4ed6\u94fe\u63a5\u662f\u9700\u8981\u767b\u5f55\u7684\n\/**=kicked-out,jwt-authc\n\n<\/code><\/pre>\n<h3>8\u3001\u6d4b\u8bd5<\/h3>\n<p>1\u3001\u6d4b\u8bd5\u767b\u5f55\u540e\uff0cjwtToken\u7684\u751f\u6210\uff0c\u4e14\u6821\u9a8c\u4f1a\u8bdd\u662f\u5426\u4f7f\u7528\u65b0\u7684jwtToken\u91cc\u7684\u4f1a\u8bddjti<\/p>\n<p>2\u3001\u6d4b\u8bd5\u81ea\u5b9a\u4e49\u8fc7\u6ee4\u5668\u662f\u5426\u751f\u6548<\/p>\n<p>\u4f7f\u7528jay\/pass\u767b\u5f55<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582109588294.png\" alt=\"1582109588294\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582109618404.png\" alt=\"1582109618404\" \/><\/p>\n<p>\u4f7f\u7528admin\/pass\u767b\u5f55<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582116805841.png\" alt=\"1582116805841\" \/><\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582116832446.png\" alt=\"1582116832446\" \/><\/p>\n<h2>\u7b2c\u5341\u4e00\u7ae0 \u5206\u5e03\u5f0f\u7edf\u4e00\u6743\u9650\u7cfb\u7edf<\/h2>\n<h3>1\u3001\u7cfb\u7edf\u9700\u6c42<\/h3>\n<h4>\u30101\u3011\u524d\u540e\u7aef\u5206\u79bb<\/h4>\n<p>\u5728\u7b2c\u5341\u7ae0\u4e2d\u6211\u4eec\u5df2\u7ecf\u5b9e\u73b0\uff0c\u4f7f\u7528jwt\u7684\u4ee4\u724c\u5b9e\u73b0\uff0c\u91cd\u5199DefaultWebSessionManager,\u4eceServletRequest\u83b7\u5f97jwtToken\u4f5c\u4e3a\u4f1a\u8bddsessionId<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.utils.EmptyUtil;\nimport io.jsonwebtoken.Claims;\nimport org.apache.shiro.web.servlet.ShiroHttpServletRequest;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.apache.shiro.web.util.WebUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.Serializable;\n\n\/**\n * @Description \u91cd\u5199Jwt\u4f1a\u8bdd\u7ba1\u7406\n *\/\n\npublic class ShiroSessionManager extends DefaultWebSessionManager {\n\n    private static final String AUTHORIZATION = \"jwtToken\";\n\n    private static final String REFERENCED_SESSION_ID_SOURCE = \"Stateless request\";\n\n    public ShiroSessionManager(){\n        super();\n    }\n\n    @Autowired\n    JwtTokenManager jwtTokenManager;\n\n    @Override\n    protected Serializable getSessionId(ServletRequest request, ServletResponse response){\n        String jwtToken = WebUtils.toHttp(request).getHeader(AUTHORIZATION);\n        if(EmptyUtil.isNullOrEmpty(jwtToken)){\n            \/\/\u5982\u679c\u6ca1\u6709\u643a\u5e26id\u53c2\u6570\u5219\u6309\u7167\u7236\u7c7b\u7684\u65b9\u5f0f\u5728cookie\u8fdb\u884c\u83b7\u53d6\n            return super.getSessionId(request, response);\n        }else{\n            \/\/\u5982\u679c\u8bf7\u6c42\u5934\u4e2d\u6709 authToken \u5219\u5176\u503c\u4e3ajwtToken\uff0c\u7136\u540e\u89e3\u6790\u51fa\u4f1a\u8bddsession\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);\n            Claims decode = jwtTokenManager.decodeToken(jwtToken);\n            String id = (String) decode.get(\"jti\");\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);\n            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);\n            return id;\n        }\n    }\n\n}\n\n\n<\/code><\/pre>\n<h4>\u30102\u3011\u96c6\u4e2d\u5f0f\u4f1a\u8bdd<\/h4>\n<p>\u5728\u7b2c\u4e03\u7ae0\u4e2dRedisSessionDao\u7ee7\u627fAbstractSessionDAO\uff0c\u91cd\u5199\u4e86\u4f1a\u8bdd\u7684\u521b\u5efa\u3001\u8bfb\u53d6\u3001\u4fee\u6539\u7b49\u64cd\u4f5c\uff0c\u5168\u90e8\u7f13\u5b58\u4e8eredis\u4e2d<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.utils.ShiroRedissionSerialize;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.session.mgt.eis.AbstractSessionDAO;\nimport org.redisson.api.RBucket;\nimport org.redisson.api.RedissonClient;\n\nimport javax.annotation.Resource;\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\n\n\/**\n * @Description \u5b9e\u73b0shiro session\u7684memcached\u96c6\u4e2d\u5f0f\u7ba1\u7406~\n *\/\n@Log4j2\npublic class RedisSessionDao extends AbstractSessionDAO {\n\n    @Resource(name = \"redissonClientForShiro\")\n    RedissonClient redissonClient;\n\n    private Long globalSessionTimeout;\n\n    @Override\n    protected Serializable doCreate(Session session) {\n        Serializable sessionId = generateSessionId(session);\n        assignSessionId(session, sessionId);\n\/\/      log.info(\"=============\u521b\u5efasessionId:{}\",sessionId);\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString());\n        sessionIdRBucket.trySet(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);\n        return sessionId;\n    }\n\n    @Override\n    protected Session doReadSession(Serializable sessionId) {\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString());\n        Session session = (Session) ShiroRedissionSerialize.deserialize(sessionIdRBucket.get());\n\/\/      log.info(\"=============\u8bfb\u53d6sessionId:{}\",session.getId().toString());\n        return session;\n    }\n\n    @Override\n    public void delete(Session session) {\n\/\/      log.info(\"=============\u5220\u9664sessionId:{}\",session.getId().toString());\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString());\n        sessionIdRBucket.delete();\n    }\n\n    @Override\n    public Collection&lt;Session&gt; getActiveSessions() {\n        return Collections.emptySet();  \n    }\n\n    @Override\n    public void update(Session session) {\n        RBucket&lt;String&gt; sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString());\n        sessionIdRBucket.set(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);\n\/\/      log.info(\"=============\u4fee\u6539sessionId:{}\",session.getId().toString());\n    }\n\n    public void setGlobalSessionTimeout(Long globalSessionTimeout) {\n        this.globalSessionTimeout = globalSessionTimeout;\n    }\n}\n\n\n\n<\/code><\/pre>\n<h4>\u30103\u3011\u8ba4\u8bc1\u4e0e\u9274\u6743\u670d\u52a1\u5316<\/h4>\n<p>\u7b2c\u516d\u7ae0\u4e2d\uff0c\u6211\u4eec\u5b9e\u73b0\u4e86realm\u7684\u7f13\u5b58\u673a\u5236\uff0c\u8fd9\u91cc\u6211\u4eec\u4f1a\u628aUserBridgeService\u4f7f\u7528dubbo\u670d\u52a1\u5316<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1581844376847.png\" alt=\"\" \/><\/p>\n<p>\u5176\u76ee\u7684\u4f7f\u5f97\u5b9e\u9645\u9879\u76ee\u4e2d\u7684\u8ba4\u8bc1\u4e0e\u9274\u6743\u8d70dubbo\uff0c\u51cf\u5c11\u670d\u52a1\u5668\u538b\u529b<\/p>\n<h4>\u30104\u3011\u52a8\u6001\u8fc7\u6ee4\u5668\u94fe<\/h4>\n<p>\u5728\u7b2c\u5341\u7ae0\u4e2d\uff0c\u6211\u4eec\u52a0\u8f7d\u8fc7\u6ee4\u5668\u94fe\u7684\u65b9\u5f0f<\/p>\n<pre><code class=\"language-properties line-numbers\">#\u9759\u6001\u8d44\u6e90\u4e0d\u8fc7\u6ee4\n\/static\/**=anon\n#\u767b\u5f55\u94fe\u63a5\u4e0d\u8fc7\u6ee4\n\/login\/**=anon\n#\u8bbf\u95ee\/resource\/**\u9700\u8981\u6709admin\u7684\u89d2\u8272\n#\/resource\/**=role-or[MangerRole,SuperAdmin]\n#\/role\/** =jwt-roles[SuperAdmin]\n\/resource\/** =jwt-perms[role:listInitialize]\n#\u5176\u4ed6\u94fe\u63a5\u662f\u9700\u8981\u767b\u5f55\u7684\n\/**=kicked-out,jwt-authc\n\n<\/code><\/pre>\n<p>\u5728\u7edf\u4e00\u9274\u6743\u7cfb\u7edf\u4e2d\uff0c\u6211\u4eec\u4e0d\u53ef\u80fd\u6bcf\u6b21\u53d1\u5e03\u65b0\u7684\u8fc7\u6ee4\u5668\u94fe\uff0c\u5c31\u53bb\u91cd\u542f\u670d\u52a1\u5668\uff0c\u6211\u4eec\u66f4\u5e0c\u671b\u53ef\u4ee5\u52a8\u6001\u7ba1\u7406\u8fc7\u6ee4\u5668\u94fe<\/p>\n<h4>\u30105\u3011\u6743\u9650\u5ba2\u6237\u7aef<\/h4>\n<p>shiro-client\u4f5c\u4e3ajar\u7684\u4f9d\u8d56\uff0c\u6ee1\u8db3\u4ee5\u4e0b\u9700\u6c42\uff1a<\/p>\n<p>1\u3001\u975e\u4fb5\u5165\u5f0f\uff1a\u4f7f\u7528\u8005\u53ea\u9700\u8981\u5bf9jar\u4f9d\u8d56\u548c\u505a\u5c11\u91cf\u7684\u914d\u7f6e\uff0c\u5c31\u53ef\u4ee5\u8fbe\u5230\u7edf\u4e00\u9274\u6743\u7684\u76ee\u6807<\/p>\n<p>2\u3001\u53ef\u6269\u5c55\u6027\uff1a\u7528\u6237\u9664\u4f7f\u7528\u63d0\u4f9b\u7684\u8fc7\u6ee4\u5668\u5916\uff0c\u53ef\u4ee5\u8f7b\u677e\u5b89\u81ea\u5df1\u7684\u4e1a\u52a1\u53bb\u5b9a\u4e49\u8fc7\u6ee4\u5668<\/p>\n<p>3\u3001\u96c6\u4e2d\u5f0f\u7ba1\u7406\uff1a\u4f9d\u8d56jar\u4e4b\u540e\uff0cshiro-mgt\u540e\u53f0\u53ef\u4ee5\u540c\u65f6\u7ba1\u63a7\u591a\u4e2a\u5e73\u53f0\u7684\u6743\u9650\u7684\u8ba4\u8bc1\u3001\u9274\u6743\u3001\u53ca\u52a8\u6001\u914d\u7f6e\u8fc7\u6ee4\u5668\u94fe<\/p>\n<h4>\u30106\u3011\u7f51\u5173\u5e73\u53f0<\/h4>\n<p>springboot-shiro-gateway:<\/p>\n<p>1\u3001\u4f9d\u8d56shiro-client\u9879\u76ee\u4f5c\u4e3a\u6743\u9650\u7684\u88ab\u63a7\u5236\u5c42<\/p>\n<p>2\u3001\u5b9e\u73b0dubbo\u4f20\u8f93\u534f\u8bae\u5230HTTP\u4f20\u8f93\u534f\u8bae\u7684\u8f6c\u5316\uff0c\u5f53\u7136\u8fd9\u91cc\u63d0\u4f9b\u7684\u4e3a\u901a\u7528\u7684\u8f6c\u6362\u65b9\u5f0f\u3002<\/p>\n<p>3\u3001\u53ef\u590d\u5236\u3001\u590d\u5236\u540e\u53ea\u9700\u8981\u5728shiro-mgt\u540e\u53f0\u4e2d\u505a\u7b80\u5355\u7684\u914d\u7f6e\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u4e00\u4e2a\u65b0\u7f51\u5173\u7684\u63a5\u5165<\/p>\n<h3>2\u3001\u67b6\u6784\u8bbe\u8ba1<\/h3>\n<h4>\u30101\u3011\u7cfb\u7edf\u7f51\u7edc\u901a\u8baf<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582876876486.png\" alt=\"1582876876486\" \/><\/p>\n<p>1\u3001\u7f51\u5173\u670d\u52a1\u96c6\u7fa4\u6027\uff0c\u540c\u65f6\u5b9e\u73b0\u4f1a\u8bdd\u7684\u7edf\u4e00\u7ba1\u7406<\/p>\n<p>2\u3001\u9274\u6743\u670d\u52a1\u96c6\u7fa4\u5316\uff0c\u63d0\u4f9b\u7edf\u4e00\u9274\u6743\u670d\u52a1<\/p>\n<p>3\u3001\u7ba1\u7406\u540e\u53f0\u96c6\u7fa4\u5316<\/p>\n<h4>\u30102\u3011\u6a21\u5757\u4f9d\u8d56\u5173\u7cfb<\/h4>\n<h5>\u30101.1\u3011springboot-shiro-parent<\/h5>\n<p>springboot-shiro-parent:\u9879\u76ee\u7edf\u4e00jar\u548cplugIn\u7684POM\u5b9a\u4e49<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582880473745.png\" alt=\"1582880473745\" \/><\/p>\n<h5>\u30101.2\u3011springboot-shiro-gateway-handler<\/h5>\n<p>\u200b       1\u3001dubbo\u4e1a\u52a1\u670d\u52a1\u8f6c\u6362http\u901a\u8baf<\/p>\n<p>\u200b       2\u3001\u8ba4\u8bc1\u4e0e\u9274\u6743\u670d\u52a1\u5316\u6d88\u8d39\u8005<\/p>\n<p>\u200b       3\u3001\u751f\u6210\u4e1a\u52a1\u670d\u52a1\u5316\u6d88\u8d39\u8005<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582880165581.png\" alt=\"1582880165581\" \/><\/p>\n<h5>\u30101.3\u3011springboot-shiro-producer<\/h5>\n<p>\u200b       \u8ba4\u8bc1\u4e0e\u9274\u6743\u670d\u52a1\u5316\u7684\u751f\u6210\u8005<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582710657210.png\" alt=\"1582710657210\" \/><\/p>\n<h5>\u30101.4\u3011springboot-shiro-mgt<\/h5>\n<p>\u200b       \u8ba4\u8bc1\u4e0e\u9274\u6743\u670d\u52a1\u5316\u6d88\u8d39\u8005<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582881763304.png\" alt=\"1582881763304\" \/><\/p>\n<h5>\u30101.5\u3011springboot-shiro-dubbo-app-handler<\/h5>\n<p>\u200b       \u751f\u4ea7\u4e1a\u52a1\u670d\u52a1\u5316\u751f\u4ea7\u8005<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582711000178.png\" alt=\"1582711000178\" \/><\/p>\n<h3>3\u3001\u8ba4\u8bc1\u9274\u6743\u670d\u52a1\u5316<\/h3>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1585539347157.png\" alt=\"1585539347157\" \/><\/p>\n<p>\u4e0a\u9762\u7684\u56fe\u89e3\u4e2d\u6211\u4eec\u53ef\u4ee5\u770b\u5230\uff0c\u8fd9\u91cc\u670d\u52a1\u5316\u7684\u4e3aUserAdapterFace<\/p>\n<p>\u6a21\u5757springboot-shiro-face\u4e2d\u7684\u63a5\u53e3\u5b9a\u4e49UserAdapterFace<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.face;\n\nimport com.itheima.shiro.vo.ResourceVo;\nimport com.itheima.shiro.vo.RoleVo;\nimport com.itheima.shiro.vo.UserVo;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7528\u6237\u670d\u52a1\u63a5\u53e3\u5b9a\u4e49\n *\/\npublic interface UserAdapterFace {\n\n    \/**\n     * @Description \u6309\u7528\u6237\u540d\u67e5\u627e\u7528\u6237\n     * @param loginName \u767b\u5f55\u540d\n     * @return\n     *\/\n    UserVo findUserByLoginName(String loginName);\n\n    \/**\n     * @Description \u67e5\u627e\u7528\u6237\u6240\u6709\u89d2\u8272\n     * @param userId \u7528\u6237Id\n     * @return\n     *\/\n    List&lt;RoleVo&gt; findRoleByUserId(String userId);\n\n    \/**\n     * @Description \u67e5\u8be2\u7528\u6237\u6709\u90a3\u4e9b\u8d44\u6e90\n     * @param userId \u7528\u6237Id\n     * @return\n     *\/\n    List&lt;ResourceVo&gt; findResourceByUserId(String userId);\n\n}\n\n\n<\/code><\/pre>\n<p>springboot-shiro-producer\u6a21\u5757\u4e2d\u7684\u751f\u4ea7\u8005UserAdapterFaceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.faceImpl;\n\nimport com.itheima.shiro.adapter.UserAdapter;\nimport com.itheima.shiro.face.UserAdapterFace;\nimport com.itheima.shiro.pojo.Resource;\nimport com.itheima.shiro.pojo.Role;\nimport com.itheima.shiro.pojo.User;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.vo.ResourceVo;\nimport com.itheima.shiro.vo.RoleVo;\nimport com.itheima.shiro.vo.UserVo;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\n *\/\n@Service(version = \"1.0.0\", retries = 3,timeout = 5000)\npublic class UserAdapterFaceImpl implements UserAdapterFace {\n\n    @Autowired\n    UserAdapter userAdapter;\n\n\n    @Override\n    public UserVo findUserByLoginName(String loginName) {\n        User user = userAdapter.findUserByLoginName(loginName);\n        if (!EmptyUtil.isNullOrEmpty(user)){\n            return BeanConv.toBean(user,UserVo.class);\n        }\n        return null;\n    }\n\n    @Override\n    public List&lt;RoleVo&gt; findRoleByUserId(String userId) {\n        List&lt;Role&gt; list = userAdapter.findRoleByUserId(userId);\n        if (!EmptyUtil.isNullOrEmpty(list)){\n            return BeanConv.toBeanList(list, RoleVo.class);\n        }\n        return null;\n    }\n\n    @Override\n    public List&lt;ResourceVo&gt; findResourceByUserId(String userId) {\n        List&lt;Resource&gt; list = userAdapter.findResourceByUserId(userId);\n        if (!EmptyUtil.isNullOrEmpty(list)){\n            return BeanConv.toBeanList(list, ResourceVo.class);\n        }\n        return null;\n    }\n}\n\n\n<\/code><\/pre>\n<p>springboot-shiro-handler\u6a21\u5757\u4e0b\u7684\u6d88\u8d39\u8005UserBridgeServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.core.SimpleCacheManager;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleMapCache;\nimport com.itheima.shiro.core.base.SimpleToken;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.face.UserAdapterFace;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.utils.ShiroUserUtil;\nimport com.itheima.shiro.vo.ResourceVo;\nimport com.itheima.shiro.vo.RoleVo;\nimport com.itheima.shiro.vo.UserVo;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.apache.shiro.util.ByteSource;\nimport org.redisson.api.RBucket;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n\n\/**\n * @Description \u6743\u9650\u6865\u63a5\u5668\n *\/\n@Slf4j\n@Component(\"userBridgeService\")\npublic class UserBridgeServiceImpl implements UserBridgeService {\n\n    @Reference(version = \"1.0.0\")\n    private UserAdapterFace userAdapterFace;\n\n    @Autowired\n    private SimpleCacheManager simpleCacheManager;\n\n    @javax.annotation.Resource(name = \"redissonClientForShiro\")\n    private RedissonClient redissonClient;\n\n    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken,String realmName) {\n        SimpleToken token = (SimpleToken)authcToken;\n        UserVo user  = this.findUserByLoginName(token.getUsername());\n        if(EmptyUtil.isNullOrEmpty(user)){\n            throw new UnknownAccountException(\"\u8d26\u53f7\u4e0d\u5b58\u5728\");\n        }\n        ShiroUser shiroUser = BeanConv.toBean(user, ShiroUser.class);\n        String sessionId = ShiroUserUtil.getShiroSessionId();\n        String cacheKeyResourcesIds = CacheConstant.RESOURCES_KEY_IDS+sessionId;\n        shiroUser.setResourceIds(this.findResourcesIdsList(cacheKeyResourcesIds,user.getId()));\n        String salt = user.getSalt();\n        String password = user.getPassWord();\n        return new SimpleAuthenticationInfo(shiroUser, password, ByteSource.Util.bytes(salt), realmName);\n    }\n\n    @Override\n    public SimpleAuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser) {\n        UserVo user = BeanConv.toBean(shiroUser, UserVo.class);\n        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();\n        String sessionId = ShiroUserUtil.getShiroSessionId();\n        \/\/\u67e5\u8be2\u7528\u6237\u62e5\u6709\u7684\u89d2\u8272\n        String cacheKeyRole = CacheConstant.ROLE_KEY + sessionId;\n        info.addRoles(this.findRoleList(cacheKeyRole, user.getId()));\n\n        \/\/\u67e5\u8be2\u7528\u6237\u62e5\u6709\u7684\u8d44\u6e90\n        String cacheKeyResources = CacheConstant.RESOURCES_KEY + sessionId;\n        info.addStringPermissions(this.findResourcesList(cacheKeyResources, user.getId()));\n        return info;\n    }\n\n\n    @Override\n    public List&lt;String&gt; findRoleList(String cacheKeyRole, String userId) {\n        List&lt;RoleVo&gt; roles = new ArrayList&lt;RoleVo&gt;();\n        if (simpleCacheManager.getCache(cacheKeyRole) != null) {\n            roles = (List&lt;RoleVo&gt;) simpleCacheManager.getCache(cacheKeyRole).get(cacheKeyRole);\n        } else {\n            roles = userAdapterFace.findRoleByUserId(userId);\n            if (roles.size() &gt; 0) {\n                \/\/\u7528\u6237\u89d2\u8272\u5b58\u653e\u5230map\n                Map&lt;Object, Object&gt; mapRole = new HashMap&lt;Object, Object&gt;();\n                mapRole.put(cacheKeyRole, roles);\n                \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n                SimpleMapCache cacheRole = new SimpleMapCache(cacheKeyRole, mapRole);\n                simpleCacheManager.createCache(cacheKeyRole, cacheRole);\n            }\n        }\n        List&lt;String&gt; rolesLabel = new ArrayList&lt;String&gt;();\n        for (RoleVo role : roles) {\n            rolesLabel.add(role.getLabel());\n        }\n        return rolesLabel;\n    }\n\n\n    @Override\n    public List&lt;String&gt; findResourcesList(String cacheKeyResources,String userId) {\n        List&lt;ResourceVo&gt; resourcesList = new ArrayList&lt;ResourceVo&gt;();\n        if (simpleCacheManager.getCache(cacheKeyResources) != null) {\n            resourcesList = (List&lt;ResourceVo&gt;) simpleCacheManager.getCache(cacheKeyResources).get(cacheKeyResources);\n        } else {\n            resourcesList = userAdapterFace.findResourceByUserId(userId);\n            if (resourcesList.size() &gt; 0) {\n                \/\/\u7528\u6237\u8d44\u6e90\u5b58\u653e\u5230map\n                Map&lt;Object, Object&gt; mapResource = new HashMap&lt;Object, Object&gt;();\n                mapResource.put(cacheKeyResources, resourcesList);\n                \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n                SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);\n                simpleCacheManager.createCache(cacheKeyResources, cacheResource);\n            }\n        }\n        List&lt;String&gt; resourcesLabel = new ArrayList&lt;String&gt;();\n        for (ResourceVo resources : resourcesList) {\n            resourcesLabel.add(resources.getLabel());\n        }\n        return resourcesLabel;\n    }\n\n\n    @Override\n    public UserVo findUserByLoginName(String loginName) {\n        String key = CacheConstant.FIND_USER_BY_LOGINNAME+loginName;\n        RBucket&lt;UserVo&gt; rBucket = redissonClient.getBucket(key);\n        UserVo user = rBucket.get();\n        if (!EmptyUtil.isNullOrEmpty(user)) {\n            return user;\n        }else {\n            user = userAdapterFace.findUserByLoginName(loginName);\n            if (!EmptyUtil.isNullOrEmpty(user)) {\n                rBucket.set(user, 300, TimeUnit.SECONDS);\n                return user;\n            }\n        }\n        rBucket.set(new UserVo(), 3, TimeUnit.SECONDS);\n        return null;\n    }\n\n    @Override\n    public List&lt;String&gt; findResourcesIdsList(String cacheKeyResources,String userId) {\n        List&lt;ResourceVo&gt; resourcesList = new ArrayList&lt;ResourceVo&gt;();\n        if (simpleCacheManager.getCache(cacheKeyResources) != null) {\n            resourcesList = (List&lt;ResourceVo&gt;) simpleCacheManager.getCache(cacheKeyResources).get(cacheKeyResources);\n        } else {\n            resourcesList = userAdapterFace.findResourceByUserId(userId);\n            if (resourcesList.size() &gt; 0) {\n                \/\/\u7528\u6237\u8d44\u6e90\u5b58\u653e\u5230map\n                Map&lt;Object, Object&gt; mapResource = new HashMap&lt;Object, Object&gt;();\n                mapResource.put(cacheKeyResources, resourcesList);\n                \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n                SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);\n                simpleCacheManager.createCache(cacheKeyResources, cacheResource);\n            }\n        }\n        List&lt;String&gt; resourcesLabel = new ArrayList&lt;String&gt;();\n        for (ResourceVo resources : resourcesList) {\n            resourcesLabel.add(resources.getId());\n        }\n        return resourcesLabel;\n    }\n\n    @Override\n    public void loadUserAuthorityToCache(ShiroUser user) {\n        String sessionId = user.getSessionId();\n        List&lt;RoleVo&gt; roles = userAdapterFace.findRoleByUserId(user.getId());\n        \/\/\u521b\u5efa\u89d2\u8272cachaeKey\n        String cacheKeyRole = CacheConstant.ROLE_KEY + sessionId;\n        \/\/\u7528\u6237\u89d2\u8272\u5b58\u653e\u5230map\n        Map&lt;Object, Object&gt; mapRole = new HashMap&lt;Object, Object&gt;();\n        mapRole.put(cacheKeyRole, roles);\n        \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n        SimpleMapCache cacheRole = new SimpleMapCache(cacheKeyRole, mapRole);\n        simpleCacheManager.createCache(cacheKeyRole, cacheRole);\n\n        List&lt;ResourceVo&gt; resourcesList = userAdapterFace.findResourceByUserId(user.getId());\n        if (resourcesList.size() &gt; 0) {\n            \/\/\u521b\u5efa\u8d44\u6e90cachaeKey\n            String cacheKeyResources = CacheConstant.RESOURCES_KEY + sessionId;\n            \/\/\u7528\u6237\u8d44\u6e90\u5b58\u653e\u5230map\n            Map&lt;Object, Object&gt; mapResource = new HashMap&lt;Object, Object&gt;();\n            mapResource.put(cacheKeyResources, resourcesList);\n            \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n            SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);\n            simpleCacheManager.createCache(cacheKeyResources, cacheResource);\n        }\n    }\n}\n\n\n<\/code><\/pre>\n<p>\u901a\u8fc7\u4e0a\u9762\u7684\u6539\u9020\uff0c\u6211\u4eec\u53ef\u4ee5\u53d1\u73b0\uff1a\u7528\u6237\u5728\u8ba4\u8bc1\u4e0e\u9274\u6743\u65f6\u8d70\u7684\u90fd\u662fdubbo\u7684\u670d\u52a1\uff0c\u800c\u5728\u5b9e\u9645\u4e1a\u52a1\u9879\u76ee\u4e2d\u4e0d\u4f1a\u518d\u53bb\u64cd\u4f5c\u9274\u6743\u76f8\u5173\u7684\u5185\u5bb9<\/p>\n<h3>4\u3001\u52a8\u6001\u8fc7\u6ee4\u5668\u94fe<\/h3>\n<p>\u5728\u7b2c\u5341\u7ae0\u4e2d\uff0c\u6211\u4eec\u52a0\u8f7d\u8fc7\u6ee4\u5668\u94fe\u7684\u65b9\u5f0f<\/p>\n<pre><code class=\"language-properties line-numbers\">#\u9759\u6001\u8d44\u6e90\u4e0d\u8fc7\u6ee4\n\/static\/**=anon\n#\u767b\u5f55\u94fe\u63a5\u4e0d\u8fc7\u6ee4\n\/login\/**=anon\n#\u8bbf\u95ee\/resource\/**\u9700\u8981\u6709admin\u7684\u89d2\u8272\n#\/resource\/**=roleOr[MangerRole,SuperAdmin]\n#\/role\/** =jwt-roles[SuperAdmin]\n\/resource\/** =jwt-perms[role:listInitialize]\n#\u5176\u4ed6\u94fe\u63a5\u662f\u9700\u8981\u767b\u5f55\u7684\n\/**=kicked-out,jwt-authc\n\n<\/code><\/pre>\n<p>\u5728\u7edf\u8ba1\u9274\u6743\u7cfb\u7edf\u4e2d\uff0c\u6211\u4eec\u4e0d\u53ef\u80fd\u6bcf\u6b21\u53d1\u5e03\u65b0\u7684\u8fc7\u6ee4\u5668\u94fe\uff0c\u5c31\u53bb\u91cd\u542f\u670d\u52a1\u5668\uff0c\u6211\u4eec\u66f4\u5e0c\u671b\u53ef\u4ee5\u52a8\u6001\u7ba1\u7406\u8fc7\u6ee4\u5668\u94fe<\/p>\n<h4>\u30101\u3011\u9700\u6c42\u5206\u6790<\/h4>\n<p>\u5b9e\u73b0\u52a8\u6001\u8fc7\u6ee4\u5668\u94fe\uff0c\u6211\u4eec\u9700\u8981\u4fdd\u8bc1\u4ee5\u4e0b\u51e0\u4e2a\u7279\u6027\uff1a<\/p>\n<p>1\u3001\u6301\u4e45\u5316\uff1a\u539f\u6709\u7684properties\u5185\u5bb9\u653e\u5165\u6570\u636e\u5e93\uff0c<\/p>\n<p>2\u3001\u6709\u5e8f\u6027\uff1a\u56e0\u8fc7\u6ee4\u5668\u94fe\u6709\u5e8f\u52a0\u8f7d\u7684\u7279\u6027\uff0c\u8bfb\u53d6\u8fc7\u6ee4\u5668\u94fe\u7684\u65f6\u4fdd\u8bc1\u5176\u6709\u5e8f\u6027<\/p>\n<p>3\u3001\u670d\u52a1\u5316\uff1a\u8fc7\u6ee4\u5668\u94fe\u7684\u670d\u52a1\u505a\u6210dubbo\u670d\u52a1\uff0c\u505a\u5230\u96c6\u4e2d\u5f0f\u7ba1\u7406<\/p>\n<p>4\u3001\u540c\u6b65\u6027\uff1a\u4e0d\u540c\u4e1a\u52a1\u7cfb\u7edf\u5bf9\u4e8e\u8fc7\u6ee4\u5668\u94fe\u7684\u52a0\u8f7d\u9700\u8981\u540c\u6b65<\/p>\n<p>5\u3001\u70ed\u52a0\u8f7d\uff1a\u8fc7\u6ee4\u5668\u94fe\u4fee\u6539\u4e4b\u540e\uff0c\u5404\u4e2a\u4e1a\u52a1\u7cfb\u7edf\u4e0d\u9700\u8981\u91cd\u542f\u670d\u52a1\uff0c\u4ee5\u8fbe\u5230\u70ed\u52a0\u8f7d\u7684\u76ee\u7684<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582619578346.png\" alt=\"1582619578346\" \/><\/p>\n<h4>\u30102\u3011\u4ee3\u7801\u5b9e\u73b0<\/h4>\n<h5>\u30102.1\u3011\u6301\u4e45\u5316\u3001\u6709\u5e8f\u5316<\/h5>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582683705723.png\" alt=\"1582683705723\" \/><\/p>\n<p>\u4e3b\u8981\u662f\u5bf9FilterChain\u7c7b\u7684CRUD\u8fd9\u91cc\u5c31\u4e0d\u505a\u8d58\u8ff0\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\u6392\u5e8f\uff1a\u5347\u5e8f\u6392\u5217\uff0c\u4ee5\u4fdd\u969c\u8fc7\u6ee4\u5668\u94fe\u7684\u6709\u5e8f\u52a0\u8f7d<\/p>\n<h5>\u30102.2\u3011\u670d\u52a1\u5316<\/h5>\n<p>\u670d\u52a1\u5316\u8fc7\u6ee4\u5668\u94fe\u52a0\u8f7d<\/p>\n<pre><code class=\"language-properties line-numbers\">FilterChainFace:\u8fc7\u6ee4\u5668\u94fe\u6865\u63a5\u5668dubbo\u63a5\u53e3\u5c42\nFilterChainFaceImpl:\u8fc7\u6ee4\u5668\u94fe\u6865\u63a5\u5668dubbo\u63a5\u53e3\u5c42\u5b9e\u73b0\n\n<\/code><\/pre>\n<p>FilterChainFace\u63a5\u53e3<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.face;\n\nimport com.itheima.shiro.vo.FilterChainVo;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u8fc7\u6ee4\u5668\u67e5\u8be2\u63a5\u53e3\n *\/\npublic interface FilterChainFace {\n\n    public List&lt;FilterChainVo&gt; findFilterChainList();\n}\n\n\n<\/code><\/pre>\n<p>FilterChainFaceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.faceImpl;\n\nimport com.itheima.shiro.face.FilterChainFace;\nimport com.itheima.shiro.pojo.FilterChain;\nimport com.itheima.shiro.service.FilterChainService;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.vo.FilterChainVo;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\n *\/\n@Service(version = \"1.0.0\", retries = 3,timeout = 5000)\npublic class FilterChainFaceImpl implements FilterChainFace {\n\n    @Autowired\n    FilterChainService filterChainService;\n\n    @Override\n    public List&lt;FilterChainVo&gt; findFilterChainList() {\n        List&lt;FilterChain&gt; filterChainList = filterChainService.findFilterChainList();\n        if (!EmptyUtil.isNullOrEmpty(filterChainList)){\n            return BeanConv.toBeanList(filterChainList, FilterChainVo.class);\n        }\n        return null;\n    }\n}\n\n\n<\/code><\/pre>\n<p>\u8fd9\u91cc\u53ea\u662f\u7b80\u5355\u7684dubbo\u670d\u52a1\uff0c\u4e5f\u4e0d\u505a\u8d58\u8ff0<\/p>\n<h5>\u30102.3\u3011\u540c\u6b65\u6027<\/h5>\n<p>\u5b9a\u4e49\u542f\u52a8\u52a0\u8f7d\u8fc7\u6ee4\u5668\u94fe\u670d\u52a1\u540c\u6b65\uff1a<\/p>\n<pre><code class=\"language-properties line-numbers\">FilterChainBridgeService:\u8fc7\u6ee4\u5668\u94fe\u6865\u63a5\u5668service\u63a5\u53e3\u5c42\nFilterChainBridgeServiceImpl:\u8fc7\u6ee4\u5668\u94fe\u6865\u63a5\u5668service\u63a5\u53e3\u5c42\u5b9e\u73b0\n\nShiroFilerChainService:shiro\u8fc7\u6ee4\u5668\u94fe\u670d\u52a1\u52a0\u8f7d\u63a5\u53e3\nShiroFilerChainService:shiro\u8fc7\u6ee4\u5668\u94fe\u670d\u52a1\u52a0\u8f7d\u63a5\u53e3\u5b9e\u73b0\n\n\n<\/code><\/pre>\n<p>FilterChainBridgeService<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.bridge;\n\nimport com.itheima.shiro.vo.FilterChainVo;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.List;\n\n\/**\n * @Description \u8fc7\u6ee4\u5668\u94feservice\u63a5\u53e3\u5c42\n *\/\npublic interface FilterChainBridgeService {\n\n    \/**\n     * @Description \u67e5\u8be2\u6240\u6709\u6709\u6548\u7684\u8fc7\u6ee4\u5668\u94fe\n     * @return\n     *\/\n    List&lt;FilterChainVo&gt; findFilterChainList();\n\n\n\n}\n\n<\/code><\/pre>\n<p>FilterChainBridgeServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.core.bridge.FilterChainBridgeService;\nimport com.itheima.shiro.face.FilterChainFace;\nimport com.itheima.shiro.vo.FilterChainVo;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\n *\/\n@Component(\"filterChainBridgeService\")\npublic class FilterChainBridgeServiceImpl implements FilterChainBridgeService {\n\n    @Reference(version = \"1.0.0\")\n    private FilterChainFace filterChainFace;\n\n    @Override\n    public List&lt;FilterChainVo&gt; findFilterChainList() {\n\n        return filterChainFace.findFilterChainList();\n    }\n}\n\n\n<\/code><\/pre>\n<p>ShiroFilerChainService\u8fc7\u6ee4\u5668\u94fe\u540c\u6b65\u63a5\u53e3<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service;\n\nimport com.itheima.shiro.vo.FilterChainVo;\n\nimport javax.annotation.PostConstruct;\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u8fc7\u6ee4\u5668\u94fe\u540c\u6b65\u63a5\u53e3\n *\/\npublic interface ShiroFilerChainService {\n\n    \/**\n     * @Description \u542f\u52a8\u65f6\u52a0\u8f7d\u6570\u636e\u5e93\u4e2d\u7684\u8fc7\u6ee4\u5668\u94fe\n     *\/\n    void init();\n\n    \/**\n     * @Description \u521d\u59cb\u5316\u8fc7\u6ee4\u5668\u94fe\n     * @param\n     * @return\n     *\/\n    void initFilterChains(List&lt;FilterChainVo&gt; FilterChainVos);\n}\n\n\n<\/code><\/pre>\n<p>ShiroFilerChainServiceImpl\u8fc7\u6ee4\u5668\u94fe\u540c\u6b65\u63a5\u53e3\u5b9e\u73b0<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.service.impl;\n\nimport com.itheima.shiro.core.impl.CustomDefaultFilterChainManager;\nimport com.itheima.shiro.service.ShiroFilerChainService;\nimport com.itheima.shiro.core.bridge.FilterChainBridgeService;\nimport com.itheima.shiro.vo.FilterChainVo;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;\nimport org.apache.shiro.web.filter.mgt.NamedFilterList;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.PostConstruct;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\n\/**\n * @Description\uff1a\u8fc7\u6ee4\u5668\u94fe\u540c\u6b65\u63a5\u53e3\u5b9e\u73b0\n *\/\n@Service(\"shiroFilerChainManager\")\n@Log4j2\npublic class ShiroFilerChainServiceImpl implements ShiroFilerChainService {\n\n    \/\/\u6b64\u65f6\u6ce8\u5165\u7684\u4e3aCustomDefaultFilterChainManager\n    @Autowired\n    private CustomDefaultFilterChainManager filterChainManager;\n\n    @Autowired\n    FilterChainBridgeService filterChainBridgeService;\n\n    private Map&lt;String, NamedFilterList&gt; defaultFilterChains;\n\n    private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);\n\n    \/**\n     * @Description \u542f\u52a8\u5b9a\u65f6\u5668\uff0c\u95f4\u96942\u5206\u949f\u540c\u6b65\u6570\u636e\u5e93\u7684\u8fc7\u6ee4\u5668\u94fe\n     *\/\n    @Override\n    @PostConstruct\n    public void init() {\n        defaultFilterChains = new LinkedHashMap&lt;&gt;();\n        executor.scheduleAtFixedRate(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    initFilterChains(filterChainBridgeService.findFilterChainList());\n                } catch (Exception e) {\n                    log.error(e.getMessage(), e);\n                }\n            }\n        }, 0, 120, TimeUnit.SECONDS);\n\n    }\n\n    @Override\n    public void initFilterChains(List&lt;FilterChainVo&gt; FilterChainVos) {\n\n        \/\/1\u3001\u9996\u5148\u5220\u9664\u4ee5\u524d\u8001\u7684filter chain\u5e76\u6ce8\u518c\u9ed8\u8ba4\u7684\n        filterChainManager.getFilterChains().clear();\n\n        \/\/2\u3001\u5faa\u73afURL Filter \u6ce8\u518cfilter chain\n        for (FilterChainVo urlFilterVo : FilterChainVos) {\n            String url = urlFilterVo.getUrl();\n            String filterName = urlFilterVo.getFilterName();\n            String[] filterNames = filterName.split(\",\");\n            for (String name : filterNames) {\n                \/\/\u6ce8\u518c\u6240\u6709filter\uff0c\u5305\u542b\u81ea\u5b9a\u4e49\u7684\u8fc7\u6ee4\u5668\n                switch(name){\n                    case \"anon\":\n                        filterChainManager.addToChain(url, name);\n                        break;\n                    case \"authc\":\n                        filterChainManager.addToChain(url, name);\n                        break;\n                    case \"roles\":\n                        filterChainManager.addToChain(url, name, urlFilterVo.getRoles());\n                        break;\n                    case \"perms\":\n                        filterChainManager.addToChain(url, name,urlFilterVo.getPermissions());\n                        break;\n                    case \"role-or\":\n                        filterChainManager.addToChain(url, name,urlFilterVo.getRoles());\n                        break;\n                    case \"kicked-out\":\n                        filterChainManager.addToChain(url, name);\n                        break;\n                    case \"jwt-authc\":\n                        filterChainManager.addToChain(url, name);\n                        break;\n                    case \"jwt-roles\":\n                        filterChainManager.addToChain(url, name, urlFilterVo.getRoles());\n                        break;\n                    case \"jwt-perms\":\n                        filterChainManager.addToChain(url, name,urlFilterVo.getPermissions());\n                        break;\n                    default:\n                        break;\n                }\n            }\n        }\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30102.4\u3011\u70ed\u52a0\u8f7d<\/h5>\n<p>\u4e3a\u4e86\u5b9e\u73b0\u70ed\u52a0\u8f7d\u6211\u4eec\u9700\u8981\u5b9a\u4e49\u4ee5\u4e0b3\u4e2a\u7c7b<\/p>\n<pre><code class=\"language-properties line-numbers\">CustomDefaultFilterChainManager:\u81ea\u5b9a\u4e49\u7684\u9ed8\u8ba4\u8fc7\u6ee4\u5668\u94fe\u7ba1\u7406\u8005\nCustomPathMatchingFilterChainResolver:\u81ea\u5b9a\u4e49\u7684\u8def\u5f84\u5339\u914d\u8fc7\u6ee4\u5668\u94fe\u89e3\u6790\u5668\nCustomShiroFilterFactoryBean:\u81ea\u5b9a\u4e49shiro\u8fc7\u6ee4\u5668\u5de5\u5382bean\n\n<\/code><\/pre>\n<h6>\u30102.4.1\u3011CustomDefaultFilterChainManager<\/h6>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582685943872.png\" alt=\"1582685943872\" \/><\/p>\n<p>\u54b1\u4eec\u6765\u770b\u4e0b\u9876\u7ea7\u63a5\u53e3FilterChainManager<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport org.apache.shiro.config.Ini;\nimport org.apache.shiro.util.CollectionUtils;\nimport org.apache.shiro.util.Nameable;\nimport org.apache.shiro.util.StringUtils;\nimport org.apache.shiro.web.config.IniFilterChainResolverFactory;\nimport org.apache.shiro.web.filter.AccessControlFilter;\nimport org.apache.shiro.web.filter.authc.AuthenticationFilter;\nimport org.apache.shiro.web.filter.authz.AuthorizationFilter;\nimport org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;\nimport org.apache.shiro.web.filter.mgt.NamedFilterList;\nimport org.apache.shiro.web.filter.mgt.SimpleNamedFilterList;\n\nimport javax.annotation.PostConstruct;\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49\u9ed8\u8ba4\u8fc7\u6ee4\u5668\u7ba1\u7406\u8005\n *\/\npublic class CustomDefaultFilterChainManager extends DefaultFilterChainManager {\n\n    \/\/\u767b\u5f55\u5730\u5740\n    private String loginUrl;\n\n    \/\/\u767b\u5f55\u6210\u529f\u540e\u9ed8\u8ba4\u8df3\u8f6c\u5730\u5740\n    private String successUrl;\n\n    \/\/\u672a\u6388\u6743\u8df3\u8f6c\u5730\u5740\n    private String unauthorizedUrl;\n\n    public CustomDefaultFilterChainManager() {\n        \/\/\u6784\u5efa\u8fc7\u6ee4\u5668\n        setFilters(new LinkedHashMap&lt;String, Filter&gt;());\n        \/\/\u6784\u5efa\u8fc7\u6ee4\u5668\u94fe\n        setFilterChains(new LinkedHashMap&lt;String, NamedFilterList&gt;());\n        \/\/\u6784\u5efa\u9ed8\u8ba4\u8fc7\u6ee4\u5668\n        addDefaultFilters(true);\n    }\n\n\n\n    \/**\n     * @Description \u6ce8\u518c\u6211\u4eec\u81ea\u5b9a\u4e49\u7684\u8fc7\u6ee4\u5668\uff0c\u76f8\u5f53\u4e8eShiroFilterFactoryBean\u7684filters\u5c5e\u6027\n     * @param customFilters \u8fc7\u6ee4\u5668\n     * @return\n     *\/\n    public void setCustomFilters(Map&lt;String, Filter&gt; customFilters) {\n        for(Map.Entry&lt;String, Filter&gt; entry : customFilters.entrySet()) {\n            addFilter(entry.getKey(), entry.getValue(), false);\n        }\n    }\n\n\n    \/**\n     * @Description Spring\u5bb9\u5668\u542f\u52a8\u65f6\u8c03\u7528\n     *\/\n    @PostConstruct\n    public void init() {\n        \/\/\u914d\u7f6e\u9ed8\u8ba4\u8fc7\u6ee4\u5668\n        Map&lt;String, Filter&gt; filters = getFilters();\n\n        \/\/\u4e3a\u8fc7\u6ee4\u5668\u94fe\u914d\u7f6e\u5168\u5c40URL\u5904\u7406\u5c5e\u6027\n        for (Filter filter : filters.values()) {\n            applyGlobalPropertiesIfNecessary(filter);\n        }\n    }\n\n    \/**\n     * @Description \u6b64\u65f6\u4ea4\u4e8espring\u5bb9\u5668\u51fa\u4e8b\u5316\uff0c\u8fd9\u91cc\u5ffd\u7565\n     *\/\n    @Override\n    protected void initFilter(Filter filter) {\n    }\n\n    private void applyGlobalPropertiesIfNecessary(Filter filter) {\n        applyLoginUrlIfNecessary(filter);\n        applySuccessUrlIfNecessary(filter);\n        applyUnauthorizedUrlIfNecessary(filter);\n    }\n\n    private void applyLoginUrlIfNecessary(Filter filter) {\n        String loginUrl = getLoginUrl();\n        if (StringUtils.hasText(loginUrl) &amp;&amp; (filter instanceof AccessControlFilter)) {\n            AccessControlFilter acFilter = (AccessControlFilter) filter;\n            \/\/only apply the login url if they haven't explicitly configured one already:\n            String existingLoginUrl = acFilter.getLoginUrl();\n            if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {\n                acFilter.setLoginUrl(loginUrl);\n            }\n        }\n    }\n\n    private void applySuccessUrlIfNecessary(Filter filter) {\n        String successUrl = getSuccessUrl();\n        if (StringUtils.hasText(successUrl) &amp;&amp; (filter instanceof AuthenticationFilter)) {\n            AuthenticationFilter authcFilter = (AuthenticationFilter) filter;\n            \/\/only apply the successUrl if they haven't explicitly configured one already:\n            String existingSuccessUrl = authcFilter.getSuccessUrl();\n            if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) {\n                authcFilter.setSuccessUrl(successUrl);\n            }\n        }\n    }\n\n    private void applyUnauthorizedUrlIfNecessary(Filter filter) {\n        String unauthorizedUrl = getUnauthorizedUrl();\n        if (StringUtils.hasText(unauthorizedUrl) &amp;&amp; (filter instanceof AuthorizationFilter)) {\n            AuthorizationFilter authzFilter = (AuthorizationFilter) filter;\n            \/\/only apply the unauthorizedUrl if they haven't explicitly configured one already:\n            String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();\n            if (existingUnauthorizedUrl == null) {\n                authzFilter.setUnauthorizedUrl(unauthorizedUrl);\n            }\n        }\n    }\n\n\n\n    public String getLoginUrl() {\n        return loginUrl;\n    }\n\n    public void setLoginUrl(String loginUrl) {\n        this.loginUrl = loginUrl;\n    }\n\n    public String getSuccessUrl() {\n        return successUrl;\n    }\n\n    public void setSuccessUrl(String successUrl) {\n        this.successUrl = successUrl;\n    }\n\n    public String getUnauthorizedUrl() {\n        return unauthorizedUrl;\n    }\n\n    public void setUnauthorizedUrl(String unauthorizedUrl) {\n        this.unauthorizedUrl = unauthorizedUrl;\n    }\n\n}\n\n<\/code><\/pre>\n<p>CustomDefaultFilterChainManager\uff1a\u4e3b\u8981\u662f\u628a\u539f\u6765\u5bf9\u8c61\u7684\u521b\u5efa\u4ea4\u4e8espring\u5bb9\u5668\uff0c\u540c\u65f6\u6307\u5b9a\u8fc7\u6ee4\u5668\uff0c\u7136\u540e\u6784\u5efa\u8fc7\u6ee4\u5668\u94fe<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport org.apache.shiro.config.Ini;\nimport org.apache.shiro.util.CollectionUtils;\nimport org.apache.shiro.util.Nameable;\nimport org.apache.shiro.util.StringUtils;\nimport org.apache.shiro.web.config.IniFilterChainResolverFactory;\nimport org.apache.shiro.web.filter.AccessControlFilter;\nimport org.apache.shiro.web.filter.authc.AuthenticationFilter;\nimport org.apache.shiro.web.filter.authz.AuthorizationFilter;\nimport org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;\nimport org.apache.shiro.web.filter.mgt.NamedFilterList;\nimport org.apache.shiro.web.filter.mgt.SimpleNamedFilterList;\n\nimport javax.annotation.PostConstruct;\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\/**\n * @Description\uff1a\u81ea\u5b9a\u4e49\u9ed8\u8ba4\u8fc7\u6ee4\u5668\u7ba1\u7406\u8005\n *\/\npublic class CustomDefaultFilterChainManager extends DefaultFilterChainManager {\n\n    \/\/\u767b\u5f55\u5730\u5740\n    private String loginUrl;\n\n    \/\/\u767b\u5f55\u6210\u529f\u540e\u9ed8\u8ba4\u8df3\u8f6c\u5730\u5740\n    private String successUrl;\n\n    \/\/\u672a\u6388\u6743\u8df3\u8f6c\u5730\u5740\n    private String unauthorizedUrl;\n\n    public CustomDefaultFilterChainManager() {\n        \/\/\u6784\u5efa\u8fc7\u6ee4\u5668\n        setFilters(new LinkedHashMap&lt;String, Filter&gt;());\n        \/\/\u6784\u5efa\u8fc7\u6ee4\u5668\u94fe\n        setFilterChains(new LinkedHashMap&lt;String, NamedFilterList&gt;());\n        \/\/\u6784\u5efa\u9ed8\u8ba4\u8fc7\u6ee4\u5668\n        addDefaultFilters(true);\n    }\n\n\n\n    \/**\n     * @Description \u6ce8\u518c\u6211\u4eec\u81ea\u5b9a\u4e49\u7684\u8fc7\u6ee4\u5668\uff0c\u76f8\u5f53\u4e8eShiroFilterFactoryBean\u7684filters\u5c5e\u6027\n     * @param customFilters \u8fc7\u6ee4\u5668\n     * @return\n     *\/\n    public void setCustomFilters(Map&lt;String, Filter&gt; customFilters) {\n        for(Map.Entry&lt;String, Filter&gt; entry : customFilters.entrySet()) {\n            addFilter(entry.getKey(), entry.getValue(), false);\n        }\n    }\n\n\n    \/**\n     * @Description Spring\u5bb9\u5668\u542f\u52a8\u65f6\u8c03\u7528\n     *\/\n    @PostConstruct\n    public void init() {\n        \/\/\u914d\u7f6e\u9ed8\u8ba4\u8fc7\u6ee4\u5668\n        Map&lt;String, Filter&gt; filters = getFilters();\n        if (!CollectionUtils.isEmpty(filters)) {\n            \/\/\u6ce8\u518c\u8fc7\u6ee4\u5668\n            for (Map.Entry&lt;String, Filter&gt; entry : filters.entrySet()) {\n                \/\/\u8fc7\u6ee4\u5668\u540d\u79f0\n                String name = entry.getKey();\n                \/\/\u8fc7\u6ee4\u5668\n                Filter filter = entry.getValue();\n                if (filter instanceof Nameable) {\n                    ((Nameable) filter).setName(name);\n                }\n                \/\/\u914d\u7f6e3\u4e2aURL\n                applyGlobalPropertiesIfNecessary(filter);\n            }\n        }\n    }\n\n    \/**\n     * @Description \u6b64\u65f6\u4ea4\u4e8espring\u5bb9\u5668\u51fa\u4e8b\u5316\uff0c\u8fd9\u91cc\u5ffd\u7565\n     *\/\n    @Override\n    protected void initFilter(Filter filter) {\n    }\n\n    private void applyGlobalPropertiesIfNecessary(Filter filter) {\n        applyLoginUrlIfNecessary(filter);\n        applySuccessUrlIfNecessary(filter);\n        applyUnauthorizedUrlIfNecessary(filter);\n    }\n\n    private void applyLoginUrlIfNecessary(Filter filter) {\n        String loginUrl = getLoginUrl();\n        if (StringUtils.hasText(loginUrl) &amp;&amp; (filter instanceof AccessControlFilter)) {\n            AccessControlFilter acFilter = (AccessControlFilter) filter;\n            \/\/only apply the login url if they haven't explicitly configured one already:\n            String existingLoginUrl = acFilter.getLoginUrl();\n            if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {\n                acFilter.setLoginUrl(loginUrl);\n            }\n        }\n    }\n\n    private void applySuccessUrlIfNecessary(Filter filter) {\n        String successUrl = getSuccessUrl();\n        if (StringUtils.hasText(successUrl) &amp;&amp; (filter instanceof AuthenticationFilter)) {\n            AuthenticationFilter authcFilter = (AuthenticationFilter) filter;\n            \/\/only apply the successUrl if they haven't explicitly configured one already:\n            String existingSuccessUrl = authcFilter.getSuccessUrl();\n            if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) {\n                authcFilter.setSuccessUrl(successUrl);\n            }\n        }\n    }\n\n    private void applyUnauthorizedUrlIfNecessary(Filter filter) {\n        String unauthorizedUrl = getUnauthorizedUrl();\n        if (StringUtils.hasText(unauthorizedUrl) &amp;&amp; (filter instanceof AuthorizationFilter)) {\n            AuthorizationFilter authzFilter = (AuthorizationFilter) filter;\n            \/\/only apply the unauthorizedUrl if they haven't explicitly configured one already:\n            String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();\n            if (existingUnauthorizedUrl == null) {\n                authzFilter.setUnauthorizedUrl(unauthorizedUrl);\n            }\n        }\n    }\n\n\n\n    public String getLoginUrl() {\n        return loginUrl;\n    }\n\n    public void setLoginUrl(String loginUrl) {\n        this.loginUrl = loginUrl;\n    }\n\n    public String getSuccessUrl() {\n        return successUrl;\n    }\n\n    public void setSuccessUrl(String successUrl) {\n        this.successUrl = successUrl;\n    }\n\n    public String getUnauthorizedUrl() {\n        return unauthorizedUrl;\n    }\n\n    public void setUnauthorizedUrl(String unauthorizedUrl) {\n        this.unauthorizedUrl = unauthorizedUrl;\n    }\n\n}\n\n<\/code><\/pre>\n<h6>\u30102.4.2\u3011CustomPathMatchingFilterChainResolver<\/h6>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582687131628.png\" alt=\"1582687131628\" \/><\/p>\n<pre><code class=\"language-java line-numbers\">package org.apache.shiro.web.filter.mgt;\n\nimport javax.servlet.FilterChain;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\n\npublic interface FilterChainResolver {\n\n    \/\/\u6839\u636e\u8bf7\u6c42\u83b7\u5f97\u5bf9\u5e94\u7684\u8fc7\u6ee4\u5668\u94fe\n    FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);\n\n}\n\n\n<\/code><\/pre>\n<p>CustomPathMatchingFilterChainResolver<\/p>\n<p>\u8fd9\u91cc\u4e3b\u8981\u6838\u5fc3\u5185\u5bb9\u662f\uff1a\u6307\u5b9a\u4f7f\u7528\u8fc7\u6ee4\u5668\u94fe\u7ba1\u7406\u5668\u4e3a\u81ea\u5df1\u5b9a\u7684\u8fc7\u6ee4\u5668\u7ba1\u7406\u5668<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport org.apache.shiro.web.filter.mgt.FilterChainManager;\nimport org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.servlet.FilterChain;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.util.ArrayList;\nimport java.util.List;\n\n\npublic class CustomPathMatchingFilterChainResolver extends PathMatchingFilterChainResolver {\n\n    private CustomDefaultFilterChainManager customDefaultFilterChainManager;\n\n    public void setCustomDefaultFilterChainManager(CustomDefaultFilterChainManager customDefaultFilterChainManager) {\n        this.customDefaultFilterChainManager = customDefaultFilterChainManager;\n    }\n\n    public CustomDefaultFilterChainManager getCustomDefaultFilterChainManager() {\n        return customDefaultFilterChainManager;\n    }\n\n    @Override\n    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {\n        \/\/\u6307\u5b9a\u4f7f\u7528\u8fc7\u6ee4\u5668\u94fe\u7ba1\u7406\u5668\u4e3a\u81ea\u5df1\u5b9a\u7684\u8fc7\u6ee4\u5668\u7ba1\u7406\u5668\n        FilterChainManager filterChainManager = getCustomDefaultFilterChainManager();\n        if (!filterChainManager.hasChains()) {\n            return null;\n        }\n\n        String requestURI = getPathWithinApplication(request);\n\n        List&lt;String&gt; chainNames = new ArrayList&lt;String&gt;();\n        \/\/the 'chain names' in this implementation are actually path patterns defined by the user.  We just use them\n        \/\/as the chain name for the FilterChainManager's requirements\n        for (String pathPattern : filterChainManager.getChainNames()) {\n\n            \/\/ If the path does match, then pass on to the subclass implementation for specific checks:\n            if (pathMatches(pathPattern, requestURI)) {\n                return filterChainManager.proxy(originalChain, pathPattern);\n            }\n        }\n        return null;\n    }\n}\n\n\n<\/code><\/pre>\n<h6>\u30102.4.3\u3011CustomShiroFilterFactoryBean<\/h6>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582688545621.png\" alt=\"1582688545621\" \/><\/p>\n<pre><code class=\"language-java line-numbers\">protected AbstractShiroFilter createInstance() throws Exception {\n\n        log.debug(\"Creating Shiro Filter instance.\");\n\n        SecurityManager securityManager = getSecurityManager();\n        if (securityManager == null) {\n            String msg = \"SecurityManager property must be set.\";\n            throw new BeanInitializationException(msg);\n        }\n\n        if (!(securityManager instanceof WebSecurityManager)) {\n            String msg = \"The security manager does not implement the WebSecurityManager interface.\";\n            throw new BeanInitializationException(msg);\n        }\n\n        FilterChainManager manager = createFilterChainManager();\n\n        \/\/Expose the constructed FilterChainManager by first wrapping it in a\n        \/\/ FilterChainResolver implementation. The AbstractShiroFilter implementations\n        \/\/ do not know about FilterChainManagers - only resolvers:\n        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();\n        chainResolver.setFilterChainManager(manager);\n\n        \/\/Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built\n        \/\/FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class\n        \/\/here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts\n        \/\/injection of the SecurityManager and FilterChainResolver:\n        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);\n    }\n\n<\/code><\/pre>\n<p>ShiroFilterFactoryBean\u6e90\u7801\u6211\u4eec\u53d1\u73b0PathMatchingFilterChainResolver\u672a\u66b4\u9732set\u65b9\u6cd5\uff0c\u6211\u4eec\u6539\u5199\u4e00\u4e0b<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.impl;\n\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.filter.mgt.FilterChainManager;\nimport org.apache.shiro.web.filter.mgt.FilterChainResolver;\nimport org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;\nimport org.apache.shiro.web.mgt.WebSecurityManager;\nimport org.apache.shiro.web.servlet.AbstractShiroFilter;\nimport org.springframework.beans.factory.BeanInitializationException;\n\n\/**\n * @Description\uff1a\n *\/\npublic class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {\n\n    PathMatchingFilterChainResolver chainResolver ;\n\n    public void setChainResolver(PathMatchingFilterChainResolver chainResolver) {\n        this.chainResolver = chainResolver;\n    }\n\n    @Override\n    protected AbstractShiroFilter createInstance() throws Exception {\n\n\n        SecurityManager securityManager = getSecurityManager();\n        if (securityManager == null) {\n            String msg = \"SecurityManager property must be set.\";\n            throw new BeanInitializationException(msg);\n        }\n\n        if (!(securityManager instanceof WebSecurityManager)) {\n            String msg = \"The security manager does not implement the WebSecurityManager interface.\";\n            throw new BeanInitializationException(msg);\n        }\n\n        FilterChainManager manager = createFilterChainManager();\n\n\n        chainResolver.setFilterChainManager(manager);\n\n        \/\/Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built\n        \/\/FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class\n        \/\/here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts\n        \/\/injection of the SecurityManager and FilterChainResolver:\n        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);\n    }\n\n    private static final class SpringShiroFilter extends AbstractShiroFilter {\n\n        protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {\n            super();\n            if (webSecurityManager == null) {\n                throw new IllegalArgumentException(\"WebSecurityManager property cannot be null.\");\n            }\n            setSecurityManager(webSecurityManager);\n            if (resolver != null) {\n                setFilterChainResolver(resolver);\n            }\n        }\n    }\n}\n\n\n<\/code><\/pre>\n<h6>\u30102.4.4\u3011ShiroConfig\u6539\u9020<\/h6>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.config;\n\n\nimport com.itheima.shiro.constant.SuperConstant;\nimport com.itheima.shiro.core.ShiroDbRealm;\nimport com.itheima.shiro.core.filter.*;\nimport com.itheima.shiro.core.impl.*;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.session.mgt.eis.SessionDAO;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.redisson.Redisson;\nimport org.redisson.api.RedissonClient;\nimport org.redisson.config.Config;\nimport org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\nimport javax.servlet.Filter;\nimport java.util.HashMap;\nimport java.util.Map;\n\n\/**\n * @Description \u6743\u9650\u914d\u7f6e\u7c7b\n *\/\n@Configuration\n@ComponentScan(basePackages = {\"com.itheima.shiro.core\"})\n@EnableConfigurationProperties({ShiroRedisProperties.class})\n@Log4j2\npublic class ShiroConfig {\n\n    @Autowired\n    private ShiroRedisProperties shiroRedisProperties;\n\n    @Autowired\n    JwtTokenManager jwtTokenManager;\n\n    \/**\n     * @Description redission\u5ba2\u6237\u7aef\n     *\/\n    @Bean(\"redissonClientForShiro\")\n    public RedissonClient redissonClient() {\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5f00\u59cb======\");\n        String[] nodeList = shiroRedisProperties.getNodes().split(\",\");\n        Config config = new Config();\n        if (nodeList.length == 1) {\n            config.useSingleServer().setAddress(nodeList[0])\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        } else {\n            config.useClusterServers().addNodeAddress(nodeList)\n                    .setConnectTimeout(shiroRedisProperties.getConnectTimeout())\n                    .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize())\n                    .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout());\n        }\n        RedissonClient redissonClient =  Redisson.create(config);\n        log.info(\"=====\u521d\u59cb\u5316redissonClientForShiro\u5b8c\u6210======\");\n        return redissonClient;\n    }\n\n    \/**\n     * @Description \u521b\u5efacookie\u5bf9\u8c61\n     *\/\n    @Bean(name=\"sessionIdCookie\")\n    public SimpleCookie simpleCookie(){\n        SimpleCookie simpleCookie = new SimpleCookie();\n        simpleCookie.setName(\"ShiroSession\");\n        return simpleCookie;\n    }\n\n    \/**\n     * @Description \u7f13\u5b58\u7ba1\u7406\u5668\n     * @param\n     * @return\n     *\/\n    @Bean(name=\"shiroCacheManager\")\n    public ShiroCacheManager shiroCacheManager(){\n        return new ShiroCacheManager(shiroRedisProperties.getGlobalSessionTimeout());\n    }\n\n    \/**\n     * @Description \u6743\u9650\u7ba1\u7406\u5668\n     * @param\n     * @return\n     *\/\n    @Bean(name=\"securityManager\")\n    public DefaultWebSecurityManager defaultWebSecurityManager(){\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(shiroDbRealm());\n        securityManager.setSessionManager(shiroSessionManager());\n        securityManager.setCacheManager(shiroCacheManager());\n        return securityManager;\n    }\n\n    \/**\n     * @Description \u5bc6\u7801\u6bd4\u8f83\u5668\n     *\/\n    @Bean\n    public HashedCredentialsMatcher hashedCredentialsMatcher (){\n        RetryLimitCredentialsMatcher matcher = new RetryLimitCredentialsMatcher(SuperConstant.HASH_ALGORITHM);\n        matcher.setHashIterations(SuperConstant.HASH_INTERATIONS);\n        return matcher;\n    }\n    \/**\n     * @Description \u81ea\u5b9a\u4e49RealmImpl\n     *\/\n    @Bean(name=\"shiroDbRealm\")\n    public ShiroDbRealm shiroDbRealm(){\n        ShiroDbRealm shiroDbRealm =new ShiroDbRealmImpl();\n        shiroDbRealm.setCredentialsMatcher(hashedCredentialsMatcher());\n        return shiroDbRealm;\n    }\n\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49session\u4f1a\u8bdd\u5b58\u50a8\u7684\u5b9e\u73b0\u7c7b \uff0c\u4f7f\u7528Redis\u6765\u5b58\u50a8\u5171\u4eabsession\uff0c\u8fbe\u5230\u5206\u5e03\u5f0f\u90e8\u7f72\u76ee\u7684\n     *\/\n    @Bean(\"redisSessionDao\")\n    public SessionDAO redisSessionDao(){\n        RedisSessionDao sessionDAO =   new RedisSessionDao();\n        sessionDAO.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());\n        return sessionDAO;\n    }\n\n    \/**\n     * @Description \u4f1a\u8bdd\u7ba1\u7406\u5668\n     *\/\n    @Bean(name=\"sessionManager\")\n    public ShiroSessionManager shiroSessionManager(){\n        ShiroSessionManager sessionManager = new ShiroSessionManager();\n        sessionManager.setSessionDAO(redisSessionDao());\n        sessionManager.setSessionValidationSchedulerEnabled(false);\n        sessionManager.setSessionIdCookieEnabled(true);\n        sessionManager.setSessionIdCookie(simpleCookie());\n        sessionManager.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout());\n        return sessionManager;\n    }\n\n    \/**\n     * @Description \u4fdd\u8bc1\u5b9e\u73b0\u4e86Shiro\u5185\u90e8lifecycle\u51fd\u6570\u7684bean\u6267\u884c\n     *\/\n    @Bean(name = \"lifecycleBeanPostProcessor\")\n    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    \/**\n     * @Description AOP\u5f0f\u65b9\u6cd5\u7ea7\u6743\u9650\u68c0\u67e5\n     *\/\n    @Bean\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);\n        return defaultAdvisorAutoProxyCreator;\n    }\n\n    \/**\n     * @Description \u914d\u5408DefaultAdvisorAutoProxyCreator\u4e8b\u9879\u6ce8\u89e3\u6743\u9650\u6821\u9a8c\n     *\/\n    @Bean\n    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {\n        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();\n        aasa.setSecurityManager(defaultWebSecurityManager());\n        return new AuthorizationAttributeSourceAdvisor();\n    }\n\n    \/**\n     * @Description \u81ea\u5b9a\u4e49\u62e6\u622a\u5668\u5b9a\u4e49\n     *\/\n    private Map&lt;String, Filter&gt; filters() {\n        Map&lt;String, Filter&gt; map = new HashMap&lt;String, Filter&gt;();\n        map.put(\"role-or\", new RolesOrAuthorizationFilter());\n        map.put(\"kicked-out\", new KickedOutAuthorizationFilter(redissonClient(), redisSessionDao(), shiroSessionManager()));\n        map.put(\"jwt-authc\", new JwtAuthcFilter(jwtTokenManager));\n        map.put(\"jwt-perms\", new JwtPermsFilter());\n        map.put(\"jwt-roles\", new JwtRolesFilter());\n        return map;\n    }\n\n    \/**\n     * @Description Shiro\u8fc7\u6ee4\u5668\n     *\/\n    @Bean(\"shiroFilter\")\n    public CustomShiroFilterFactoryBean shiroFilterFactoryBean(){\n        CustomShiroFilterFactoryBean shiroFilter = new CustomShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(defaultWebSecurityManager());\n        shiroFilter.setChainResolver(filterChainResolver());\n        return shiroFilter;\n    }\n\n    @Bean\n    public CustomDefaultFilterChainManager defaultFilterChainManager(){\n        CustomDefaultFilterChainManager filterChainManager = new CustomDefaultFilterChainManager();\n        filterChainManager.setLoginUrl(\"\/login\");\n        filterChainManager.setUnauthorizedUrl(\"\/login\");\n        filterChainManager.setCustomFilters(filters());\n        return filterChainManager;\n    }\n\n    @Bean\n    CustomPathMatchingFilterChainResolver filterChainResolver(){\n        CustomPathMatchingFilterChainResolver pathMatchingFilterChainResolver = new CustomPathMatchingFilterChainResolver();\n        pathMatchingFilterChainResolver.setCustomDefaultFilterChainManager(defaultFilterChainManager());\n        return pathMatchingFilterChainResolver;\n    }\n\n}\n\n<\/code><\/pre>\n<h3>5\u3001shiro-client\u5ba2\u6237\u7aef<\/h3>\n<p>shiro-client\u4f5c\u4e3ajar\u7684\u4f9d\u8d56\uff0c\u6ee1\u8db3\u4ee5\u4e0b\u9700\u6c42\uff1a<\/p>\n<p>1\u3001\u975e\u4fb5\u5165\u5f0f\uff1a\u4f7f\u7528\u8005\u53ea\u9700\u8981\u5bf9jar\u4f9d\u8d56\u548c\u505a\u5c11\u91cf\u7684\u914d\u7f6e\uff0c\u5c31\u53ef\u4ee5\u8fbe\u5230\u7edf\u4e00\u9274\u6743\u7684\u76ee\u6807<\/p>\n<p>2\u3001\u53ef\u6269\u5c55\u6027\uff1a\u7528\u6237\u9664\u4f7f\u7528\u63d0\u4f9b\u7684\u8fc7\u6ee4\u5668\u5916\uff0c\u53ef\u4ee5\u8f7b\u677e\u5b89\u81ea\u5df1\u7684\u4e1a\u52a1\u533a\u5b9a\u4e49\u8fc7\u6ee4\u5668<\/p>\n<p>3\u3001\u96c6\u4e2d\u5f0f\u7ba1\u7406\uff1a\u4f9d\u8d56jar\u4e4b\u540e\uff0cshiro-mgt\u540e\u53f0\u53ef\u4ee5\u540c\u65f6\u7ba1\u63a7\u591a\u4e2a\u5e73\u53f0\u7684\u6743\u9650\u7684\u8ba4\u8bc1\u3001\u9274\u6743\u3001\u53ca\u52a8\u6001\u914d\u7f6e\u8fc7\u6ee4\u5668\u94fe<\/p>\n<h4>\u30101\u3011\u6a21\u5757\u4f9d\u8d56\u5173\u7cfb<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582688991837.png\" alt=\"1582688991837\" \/><\/p>\n<h4>\u30102\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p>springboot-shiro-framework-client\u9879\u76ee\u5411\u4e0a\u7ee7\u627f\u4e86springboot-shiro-framework-core\u9879\u76ee\uff0cspringboot-shiro-framework-core\u662f\u4e3b\u8981\u5b9e\u73b0\u8ba4\u8bc1\u3001\u9274\u6743\u3001\u8fc7\u6ee4\u5668\u5b9a\u4e49\u3001\u4f1a\u8bdd\u7edf\u4e00\u3001realm\u7f13\u5b58\u7684\u6838\u5fc3\u9879\u76ee\u3002<\/p>\n<p>springboot-shiro-framework-client\u9879\u76ee\u4ee5jar\u7684\u65b9\u5f0f\u88ab\u9700\u8981\u505a\u6743\u9650\u63a7\u5236\u7684gateway\u9879\u76ee\u6240\u4f9d\u8d56\uff0c\u518d\u7531gateway\u901a\u8fc7\u5bf9springboot-shiro-producer\u7684dubbo\u6d88\u8d39\uff0c\u4ee5\u8fbe\u5230\u7edf\u4e00\u8ba4\u8bc1\u3001\u9274\u6743<\/p>\n<p>springboot-shiro-framework-client\u6a21\u5757\u5b9e\u73b0\u4e86springboot-shiro-framework-core\u63a5\u53e3\u76843\u4e2a\u7c7b\uff1a<\/p>\n<pre><code class=\"language-properties line-numbers\">UserBridgeServiceImpl:\u63d0\u4f9b\u7528\u6237\u57fa\u672c\u8d44\u6e90\u64cd\u4f5c\u7684\u4e1a\u52a1\u5b9e\u73b0\nFilterChainBridgeServiceImpl:\u63d0\u4f9b\u8fc7\u6ee4\u5668\u94fe\u63a5\u53e3\u7684\u67e5\u8be2\nResourceBridgeServiceImpl:\u63d0\u4f9b\u8d44\u6e90\u67e5\u8be2\n\n<\/code><\/pre>\n<p>UserBridgeServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.constant.CacheConstant;\nimport com.itheima.shiro.core.SimpleCacheManager;\nimport com.itheima.shiro.core.base.ShiroUser;\nimport com.itheima.shiro.core.base.SimpleMapCache;\nimport com.itheima.shiro.core.base.SimpleToken;\nimport com.itheima.shiro.core.bridge.UserBridgeService;\nimport com.itheima.shiro.face.UserAdapterFace;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.utils.ShiroUserUtil;\nimport com.itheima.shiro.vo.ResourceVo;\nimport com.itheima.shiro.vo.RoleVo;\nimport com.itheima.shiro.vo.UserVo;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.apache.shiro.util.ByteSource;\nimport org.redisson.api.RBucket;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n\n\/**\n * @Description \u6743\u9650\u6865\u63a5\u5668\n *\/\n@Slf4j\n@Component(\"userBridgeService\")\npublic class UserBridgeServiceImpl implements UserBridgeService {\n\n    @Reference(version = \"1.0.0\")\n    private UserAdapterFace userAdapterFace;\n\n    @Autowired\n    private SimpleCacheManager simpleCacheManager;\n\n    @javax.annotation.Resource(name = \"redissonClientForShiro\")\n    private RedissonClient redissonClient;\n\n    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken,String realmName) {\n        SimpleToken token = (SimpleToken)authcToken;\n        UserVo user  = this.findUserByLoginName(token.getUsername());\n        if(EmptyUtil.isNullOrEmpty(user)){\n            throw new UnknownAccountException(\"\u8d26\u53f7\u4e0d\u5b58\u5728\");\n        }\n        ShiroUser shiroUser = BeanConv.toBean(user, ShiroUser.class);\n        String sessionId = ShiroUserUtil.getShiroSessionId();\n        String cacheKeyResourcesIds = CacheConstant.RESOURCES_KEY_IDS+sessionId;\n        shiroUser.setResourceIds(this.findResourcesIdsList(cacheKeyResourcesIds,user.getId()));\n        String salt = user.getSalt();\n        String password = user.getPassWord();\n        return new SimpleAuthenticationInfo(shiroUser, password, ByteSource.Util.bytes(salt), realmName);\n    }\n\n    @Override\n    public SimpleAuthorizationInfo getAuthorizationInfo(ShiroUser shiroUser) {\n        UserVo user = BeanConv.toBean(shiroUser, UserVo.class);\n        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();\n        String sessionId = ShiroUserUtil.getShiroSessionId();\n        \/\/\u67e5\u8be2\u7528\u6237\u62e5\u6709\u7684\u89d2\u8272\n        String cacheKeyRole = CacheConstant.ROLE_KEY + sessionId;\n        info.addRoles(this.findRoleList(cacheKeyRole, user.getId()));\n\n        \/\/\u67e5\u8be2\u7528\u6237\u62e5\u6709\u7684\u8d44\u6e90\n        String cacheKeyResources = CacheConstant.RESOURCES_KEY + sessionId;\n        info.addStringPermissions(this.findResourcesList(cacheKeyResources, user.getId()));\n        return info;\n    }\n\n\n    @Override\n    public List&lt;String&gt; findRoleList(String cacheKeyRole, String userId) {\n        List&lt;RoleVo&gt; roles = new ArrayList&lt;RoleVo&gt;();\n        if (simpleCacheManager.getCache(cacheKeyRole) != null) {\n            roles = (List&lt;RoleVo&gt;) simpleCacheManager.getCache(cacheKeyRole).get(cacheKeyRole);\n        } else {\n            roles = userAdapterFace.findRoleByUserId(userId);\n            if (roles.size() &gt; 0) {\n                \/\/\u7528\u6237\u89d2\u8272\u5b58\u653e\u5230map\n                Map&lt;Object, Object&gt; mapRole = new HashMap&lt;Object, Object&gt;();\n                mapRole.put(cacheKeyRole, roles);\n                \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n                SimpleMapCache cacheRole = new SimpleMapCache(cacheKeyRole, mapRole);\n                simpleCacheManager.createCache(cacheKeyRole, cacheRole);\n            }\n        }\n        List&lt;String&gt; rolesLabel = new ArrayList&lt;String&gt;();\n        for (RoleVo role : roles) {\n            rolesLabel.add(role.getLabel());\n        }\n        return rolesLabel;\n    }\n\n\n    @Override\n    public List&lt;String&gt; findResourcesList(String cacheKeyResources,String userId) {\n        List&lt;ResourceVo&gt; resourcesList = new ArrayList&lt;ResourceVo&gt;();\n        if (simpleCacheManager.getCache(cacheKeyResources) != null) {\n            resourcesList = (List&lt;ResourceVo&gt;) simpleCacheManager.getCache(cacheKeyResources).get(cacheKeyResources);\n        } else {\n            resourcesList = userAdapterFace.findResourceByUserId(userId);\n            if (resourcesList.size() &gt; 0) {\n                \/\/\u7528\u6237\u8d44\u6e90\u5b58\u653e\u5230map\n                Map&lt;Object, Object&gt; mapResource = new HashMap&lt;Object, Object&gt;();\n                mapResource.put(cacheKeyResources, resourcesList);\n                \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n                SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);\n                simpleCacheManager.createCache(cacheKeyResources, cacheResource);\n            }\n        }\n        List&lt;String&gt; resourcesLabel = new ArrayList&lt;String&gt;();\n        for (ResourceVo resources : resourcesList) {\n            resourcesLabel.add(resources.getLabel());\n        }\n        return resourcesLabel;\n    }\n\n\n    @Override\n    public UserVo findUserByLoginName(String loginName) {\n        String key = CacheConstant.FIND_USER_BY_LOGINNAME+loginName;\n        RBucket&lt;UserVo&gt; rBucket = redissonClient.getBucket(key);\n        UserVo user = rBucket.get();\n        if (!EmptyUtil.isNullOrEmpty(user)) {\n            return user;\n        }else {\n            user = userAdapterFace.findUserByLoginName(loginName);\n            if (!EmptyUtil.isNullOrEmpty(user)) {\n                rBucket.set(user, 300, TimeUnit.SECONDS);\n                return user;\n            }\n        }\n        rBucket.set(new UserVo(), 3, TimeUnit.SECONDS);\n        return null;\n    }\n\n    @Override\n    public List&lt;String&gt; findResourcesIdsList(String cacheKeyResources,String userId) {\n        List&lt;ResourceVo&gt; resourcesList = new ArrayList&lt;ResourceVo&gt;();\n        if (simpleCacheManager.getCache(cacheKeyResources) != null) {\n            resourcesList = (List&lt;ResourceVo&gt;) simpleCacheManager.getCache(cacheKeyResources).get(cacheKeyResources);\n        } else {\n            resourcesList = userAdapterFace.findResourceByUserId(userId);\n            if (resourcesList.size() &gt; 0) {\n                \/\/\u7528\u6237\u8d44\u6e90\u5b58\u653e\u5230map\n                Map&lt;Object, Object&gt; mapResource = new HashMap&lt;Object, Object&gt;();\n                mapResource.put(cacheKeyResources, resourcesList);\n                \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n                SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);\n                simpleCacheManager.createCache(cacheKeyResources, cacheResource);\n            }\n        }\n        List&lt;String&gt; resourcesLabel = new ArrayList&lt;String&gt;();\n        for (ResourceVo resources : resourcesList) {\n            resourcesLabel.add(resources.getId());\n        }\n        return resourcesLabel;\n    }\n\n    @Override\n    public void loadUserAuthorityToCache(ShiroUser user) {\n        String sessionId = user.getSessionId();\n        List&lt;RoleVo&gt; roles = userAdapterFace.findRoleByUserId(user.getId());\n        \/\/\u521b\u5efa\u89d2\u8272cachaeKey\n        String cacheKeyRole = CacheConstant.ROLE_KEY + sessionId;\n        \/\/\u7528\u6237\u89d2\u8272\u5b58\u653e\u5230map\n        Map&lt;Object, Object&gt; mapRole = new HashMap&lt;Object, Object&gt;();\n        mapRole.put(cacheKeyRole, roles);\n        \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n        SimpleMapCache cacheRole = new SimpleMapCache(cacheKeyRole, mapRole);\n        simpleCacheManager.createCache(cacheKeyRole, cacheRole);\n\n        List&lt;ResourceVo&gt; resourcesList = userAdapterFace.findResourceByUserId(user.getId());\n        if (resourcesList.size() &gt; 0) {\n            \/\/\u521b\u5efa\u8d44\u6e90cachaeKey\n            String cacheKeyResources = CacheConstant.RESOURCES_KEY + sessionId;\n            \/\/\u7528\u6237\u8d44\u6e90\u5b58\u653e\u5230map\n            Map&lt;Object, Object&gt; mapResource = new HashMap&lt;Object, Object&gt;();\n            mapResource.put(cacheKeyResources, resourcesList);\n            \/\/\u65b0\u5efaSimpleMapCache\u5b9e\u4f8b\u5e76\u653e\u5165\u7f13\u5b58\u7ba1\u7406\u5668\n            SimpleMapCache cacheResource = new SimpleMapCache(cacheKeyResources, mapResource);\n            simpleCacheManager.createCache(cacheKeyResources, cacheResource);\n        }\n    }\n}\n\n\n<\/code><\/pre>\n<p>FilterChainBridgeServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.core.bridge.FilterChainBridgeService;\nimport com.itheima.shiro.face.FilterChainFace;\nimport com.itheima.shiro.vo.FilterChainVo;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u8fc7\u6ee4\u5668\u94fe\u67e5\u8be2\n *\/\n@Component(\"filterChainBridgeService\")\npublic class FilterChainBridgeServiceImpl implements FilterChainBridgeService {\n\n    @Reference(version = \"1.0.0\")\n    private FilterChainFace filterChainFace;\n\n\n    @Override\n    public List&lt;FilterChainVo&gt; findFilterChainList() {\n\n        return filterChainFace.findFilterChainList();\n    }\n}\n\n\n<\/code><\/pre>\n<p>ResourceBridgeServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.core.bridge.ResourceBridgeService;\nimport com.itheima.shiro.face.ResourceAdapterFace;\nimport com.itheima.shiro.vo.ResourceVo;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u67e5\u8be2\u8d44\u6e90\n *\/\n@Component(\"resourceBridgeService\")\npublic class ResourceBridgeServiceImpl implements ResourceBridgeService {\n\n    @Value(\"${itheima.resource.systemcode}\")\n    private String systemCode;\n\n    @Reference(version = \"1.0.0\")\n    ResourceAdapterFace resourceAdapterFace;\n\n    @Override\n    public List&lt;ResourceVo&gt; findValidResourceVoAll(String systemCode) {\n        return resourceAdapterFace.findValidResourceVoAll(systemCode);\n    }\n}\n\n\n<\/code><\/pre>\n<p>\u4ece\u4e2d\u6211\u4eec\u53ef\u4ee5\u770b\u52303\u4e2a\u7c7b\u8c03\u7528\u4e86springboot-shiro-handler\u4e2d\u63d0\u4f9b\u7684dubbo\u9274\u6743\u670d\u52a1\u5316\u5185\u5bb9<\/p>\n<h3>6\u3001shiro-gateway\u7f51\u5173<\/h3>\n<h4>\u30101\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582880165581.png\" alt=\"1582880165581\" \/><\/p>\n<p>\u200b   1\u3001\u4f9d\u8d56springboot-shiro-framework-client\u5b9e\u73b0\u8ba4\u8bc1\u3001\u9274\u6743\u3001\u8fc7\u6ee4\u5668\u5b9a\u4e49\u3001\u4f1a\u8bdd\u7edf\u4e00\u3001realm\u7f13\u5b58\u7b49\u529f\u80fd<\/p>\n<p>\u200b   2\u3001springboot-shiro-mgt\u7ba1\u7406\u540e\u53f0\u6301\u4e45\u5316\u7f51\u5173\u8d44\u6e90<\/p>\n<p>\u200b   3\u3001springboot-shiro-handler\u5b9e\u73b0\u7f51\u5173\u8d44\u6e90\u67e5\u8be2\u670d\u52a1\u5316<\/p>\n<p>\u200b   4\u3001gateway-service\u4f9d\u636e\u6301\u4e45\u5316\u7684\u7f51\u5173\u8d44\u6e90\uff0c\u52a8\u6001\u521b\u5efa\u6d88\u8d39\u7aef\u670d\u52a1<\/p>\n<h4>\u30102\u3011\u4ee3\u7801\u5b9e\u73b0<\/h4>\n<h5>\u30102.1\u3011\u7f51\u5173\u8d44\u6e90\u6301\u4e45\u5316<\/h5>\n<p>\u8fd9\u91cc\u5728\u539f\u6709\u8d44\u6e90\u7684\u57fa\u7840\u4e0a\uff0c\u589e\u52a0\u7684\u7f51\u5173\u8d44\u6e90\u7684\u7ba1\u7406\uff1a<\/p>\n<p>\u200b       1\u3001\u5b9a\u4e49\u7f51\u5173systemcode\uff0c\u7528\u4ee5\u533a\u5206\u4e0d\u540c\u7f51\u5173\u7cfb\u7edf<\/p>\n<p>\u200b       2\u3001\u5b9a\u4e49\u8bbf\u95ee\u7684\u8def\u5f84<\/p>\n<p>\u200b       3\u3001\u5b9a\u4e49\u8d44\u6e90\u7684\u552f\u4e00\u6807\u8bc6\uff0c\u4f5c\u4e3a\u6743\u9650\u63a7\u5236\u7684\u6807\u8bc6<\/p>\n<p>\u200b       4\u3001\u5b9a\u4e49\u4e1a\u52a1\u7aefdubbo\u670d\u52a1\u7aef\u63a5\u53e3\u3001\u76ee\u6807\u65b9\u6cd5\u3001\u4f20\u5165\u9610\u8ff0\u3001\u8f6e\u8bad\u7b97\u6cd5\u3001\u8d85\u65f6\u65f6\u95f4\u3001\u91cd\u8bd5\u6b21\u6570\u7b49\u53c2\u6570\uff0c\u8fd9\u4e9b\u5185\u5bb9\u4f1a\u5728gateway-service\u9879\u76ee\u4e2d\u89e3\u6790<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582704703769.png\" alt=\"1582704703769\" \/><\/p>\n<h5>\u30102.2\u3011\u7f51\u5173\u8d44\u6e90\u670d\u52a1\u5316<\/h5>\n<pre><code class=\"language-properties line-numbers\">ResourceAdapterFace:\u7f51\u5173\u8d44\u6e90\u670d\u52a1\u63a5\u53e3\nResourceAdapterFaceImpl:\u7f51\u5173\u8d44\u6e90\u670d\u52a1\u63a5\u53e3\u5b9e\u73b0\n\nResourceBridgeService:\u7f51\u5173\u8d44\u6e90\u6865\u63a5\u5668\u63a5\u53e3\nResourceBridgeServiceImpl:\u7f51\u5173\u8d44\u6e90\u6865\u63a5\u5668\u63a5\u53e3\u5b9e\u73b0\n\n<\/code><\/pre>\n<p>ResourceAdapterFace<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.face;\n\nimport com.itheima.shiro.vo.ResourceVo;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7f51\u5173\u8d44\u6e90\u670d\u52a1\u63a5\u53e3\n *\/\npublic interface ResourceAdapterFace {\n\n    \/**\n     * @Description \u83b7\u5f97\u5f53\u524d\u7cfb\u7edf\u662f\u7531\u6709\u6548\u7684dubbo\u7684\u8d44\u6e90\n     *\/\n    List&lt;ResourceVo&gt; findValidResourceVoAll(String systemCode);\n}\n\n\n<\/code><\/pre>\n<p>ResourceAdapterFaceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.faceImpl;\n\nimport com.itheima.shiro.face.ResourceAdapterFace;\nimport com.itheima.shiro.pojo.Resource;\nimport com.itheima.shiro.service.ResourceService;\nimport com.itheima.shiro.utils.BeanConv;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.vo.ResourceVo;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7f51\u5173\u8d44\u6e90\u670d\u52a1\u63a5\u53e3\u5b9e\u73b0\n *\/\n@Service(version = \"1.0.0\", retries = 3,timeout = 5000)\npublic class ResourceAdapterFaceImpl implements ResourceAdapterFace {\n\n    @Autowired\n    ResourceService resourceService;\n\n    @Override\n    public List&lt;ResourceVo&gt; findValidResourceVoAll(String systemCode) {\n        List&lt;Resource&gt; resourceList =  resourceService.findValidResourceVoAll(systemCode);\n        if (!EmptyUtil.isNullOrEmpty(resourceList)){\n            return BeanConv.toBeanList(resourceList, ResourceVo.class);\n        }\n        return  null;\n    }\n}\n\n\n<\/code><\/pre>\n<p>ResourceBridgeService<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.core.bridge;\n\nimport com.itheima.shiro.vo.ResourceVo;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7f51\u5173\u8d44\u6e90\u6865\u63a5\u5668\u63a5\u53e3\n *\/\npublic interface ResourceBridgeService {\n\n    \/**\n     * @Description \u67e5\u8be2\u5f53\u524d\u7cfb\u7edf\u6240\u6709\u6709\u6548\u7684DUBBO\u7c7b\u578b\u7684\u670d\u52a1\n     * @param systemCode \u7cfb\u7edf\u7f16\u53f7\uff1a\u4e0emgt\u6dfb\u52a0\u7cfb\u7edf\u7f16\u53f7\u76f8\u540c\n     * @return\n     *\/\n    public List&lt;ResourceVo&gt; findValidResourceVoAll(String systemCode);\n}\n\n\n<\/code><\/pre>\n<p>ResourceBridgeServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.client;\n\nimport com.itheima.shiro.core.bridge.ResourceBridgeService;\nimport com.itheima.shiro.face.ResourceAdapterFace;\nimport com.itheima.shiro.vo.ResourceVo;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n\/**\n * @Description\uff1a\u7f51\u5173\u8d44\u6e90\u6865\u63a5\u5668\u63a5\u53e3\u5b9e\u73b0\n *\/\n@Component(\"resourceBridgeService\")\npublic class ResourceBridgeServiceImpl implements ResourceBridgeService {\n\n    @Value(\"${itheima.resource.systemcode}\")\n    private String systemCode;\n\n    @Reference(version = \"1.0.0\")\n    ResourceAdapterFace resourceAdapterFace;\n\n    @Override\n    public List&lt;ResourceVo&gt; findValidResourceVoAll(String systemCode) {\n        return resourceAdapterFace.findValidResourceVoAll(systemCode);\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30102.3\u3011\u52a8\u6001\u6d88\u8d39\u7aef<\/h5>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582882166870.png\" alt=\"1582882166870\" \/><\/p>\n<pre><code class=\"language-properties line-numbers\">CacheWare:\u7f13\u5b58\u4ed3\u5e93\n\nCacheWareService:\u7f13\u5b58\u4ed3\u5e93\u670d\u52a1\u63a5\u53e3\nCacheWareServiceImpl:\u7f13\u5b58\u4ed3\u5e93\u670d\u52a1\u63a5\u53e3\u5b9e\u73b0\n\nCacheWareSyncService:\u7f13\u5b58\u4ed3\u5e93\u540c\u6b65\u670d\u52a1\u63a5\u53e3\nCacheWareSyncServiceImpl:\u7f13\u5b58\u4ed3\u5e93\u540c\u6b65\u670d\u52a1\u63a5\u53e3\u5b9e\u73b0\n\nLoginAction:\u767b\u5f55\u76f8\u5e94\u63a5\u53e3\nGateWayController:\u76f8\u5e94\u5c42\u7684\u7edf\u4e00\u5165\u53e3\n\n<\/code><\/pre>\n<h6>\u30102.3.1\u3011CacheWareService<\/h6>\n<p>\u5176\u4e3b\u8981\u8d1f\u8d23\uff1a<\/p>\n<p>1\u3001\u7f13\u5b58\u7684\u6e05\u9664<\/p>\n<p>2\u3001\u5411map\u5bb9\u5668\u4e2d\u521b\u5efa\u7f13\u5b58<\/p>\n<p>3\u3001\u83b7\u5f97\u7f13\u5b58\u4ed3\u5e93\u6267\u884c\u5bf9\u8c61<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.cache;\n\nimport com.google.common.collect.Multimap;\nimport com.itheima.shiro.pojo.CacheWare;\n\n\/**\n * @Description\uff1a\u7f13\u5b58\u4ed3\u5e93\u670d\u52a1\n *\/\npublic interface CacheWareService {\n\n    \/**\n     * @Description \u6e05\u9664\u7f13\u5b58\n     *\/\n    void clearCacheWare();\n\n    \/**\n     * @Description \u5411map\u5bb9\u5668\u4e2d\u521b\u5efa\u7f13\u5b58\n     * @param CacheWareMap\n     *\/\n    void createCacheWare(Multimap&lt;String, CacheWare&gt; CacheWareMap);\n\n    \/**\n     * @Description \u83b7\u5f97\u7f13\u5b58\u4ed3\u5e93\u6267\u884c\u5bf9\u8c61\n     * @param serviceName \u670d\u52a1\u540d\n     * @param methodName  \u65b9\u6cd5\u540d\n     * @return {@link CacheWare}\n     *\n     *\/\n    CacheWare queryCacheWare(String serviceName, String methodName);\n\n\n}\n\n\n\n<\/code><\/pre>\n<p>CacheWareServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.cache.impl;\n\nimport com.google.common.collect.ArrayListMultimap;\nimport com.google.common.collect.Multimap;\nimport com.itheima.shiro.cache.CacheWareService;\nimport com.itheima.shiro.pojo.CacheWare;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport org.springframework.stereotype.Service;\n\nimport java.util.Collection;\nimport java.util.concurrent.locks.ReentrantLock;\n\n\/**\n * @Description\uff1a\n *\/\n@Service(\"cacheWareService\")\npublic class CacheWareServiceImpl implements CacheWareService {\n\n    private Multimap&lt;String, CacheWare&gt; cacheWareMaps = ArrayListMultimap.create();\n\n    \/**\n     * \u6570\u636e\u9501\n     *\/\n    private static ReentrantLock reentrantLock = new ReentrantLock();\n\n\n    @Override\n    public void clearCacheWare() {\n        try {\n            reentrantLock.lock();\n            cacheWareMaps.clear();\n        } finally {\n            reentrantLock.unlock();\n        }\n    }\n\n\n    @Override\n    public void createCacheWare(Multimap&lt;String, CacheWare&gt; CacheWareMap) {\n        try {\n            reentrantLock.lock();\n            this.cacheWareMaps = CacheWareMap;\n        } finally {\n            reentrantLock.unlock();\n        }\n    }\n\n    @Override\n    public CacheWare queryCacheWare(String serviceName, String methodName) {\n        if (EmptyUtil.isNullOrEmpty(serviceName) || EmptyUtil.isNullOrEmpty(serviceName)) {\n            return null;\n        }\n        StringBuffer serviceNameStringBuffer = new StringBuffer(serviceName);\n        StringBuffer methodNameStringBuffer = new StringBuffer(methodName);\n        String key = serviceNameStringBuffer.append(\":\").append(methodName).toString();\n        Collection&lt;CacheWare&gt; cacheWares = cacheWareMaps.get(key);\n        return EmptyUtil.isNullOrEmpty(cacheWares) ? null : cacheWares.iterator().next();\n    }\n\n}\n\n\n\n<\/code><\/pre>\n<h6>\u30102.3.2\u3011CacheWareSyncService<\/h6>\n<p>\u5176\u4e3b\u8981\u804c\u8d23\uff1a<\/p>\n<p>1\u3001\u542f\u52a8\u65f6\u3001\u8c03\u7528CacheWareService\u7684\u521b\u5efa\u7f13\u5b58\u65b9\u6cd5\u521d\u59cb\u5316\u7f13\u5b58\u4ed3\u5e93<\/p>\n<p>2\u3001\u540c\u6b65\u7f13\u5b58\u4ed3\u5e93<\/p>\n<p>3\u3001\u7f51\u5173\u8d44\u6e90\u8f6c\u5316\u7f13\u5b58\u4ed3\u5e93\u53ef\u6267\u884c\u5bf9\u8c61<\/p>\n<p>4\u3001\u4ecedubbo\u4e2d\uff0c\u521d\u59cb\u5316\u4ee3\u7406\u5bf9\u8c61<\/p>\n<p>\u6ce8\u610f\uff1a\u4e3a\u4e86\u5728\u591a\u4e2a\u7f51\u5173\u7cfb\u7edf\u4e0b\uff0c\u63a5\u53e3\u8f6c\u6362\u7684\u65e0\u5e72\u6270\uff0c\u8bfb\u53d6\u7684\u53ea\u662f\u672c\u7f51\u5173\u6240\u5bf9\u5e94\u7684\u8d44\u6e90<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.cache;\n\nimport com.itheima.shiro.pojo.CacheWare;\nimport com.itheima.shiro.vo.ResourceVo;\n\n\/**\n * @Description\uff1a\u7f13\u5b58\u4ed3\u5e93\u540c\u6b65\u5237\u65b0\n *\/\npublic interface CacheWareSyncService {\n\n    \/**\n     * @Description \u521d\u59cb\u5316\u7f13\u5b58\u4ed3\u5e93\n     *\/\n    void initCacheWare();\n\n    \/**\n     * @Description \u540c\u6b65\u7f13\u5b58\u4ed3\u5e93\n     *\/\n    void refreshCacheWare();\n\n    \/**\n     * @Description \u8d44\u6e90\u8f6c\u6362\u7f13\u5b58\u4ed3\u5e93\u5bf9\u8c61\n     *\/\n    CacheWare resourceConvCacheWare(ResourceVo resource);\n\n    \/**\n     * @Description \u521d\u59cb\u5316\u4ee3\u7406\u5bf9\u8c61\n     * @param interfaceClass \u63a5\u53e3\n     * @param loadbalance \u7b97\u6cd5\n     * @param version \u7248\u672c\n     * @param timeout \u8d85\u65f6\u65f6\u95f4\n     * @param retries \u91cd\u8bd5\u6b21\u6570\n     *\/\n    Object initProxy(Class&lt;?&gt; interfaceClass,\n                     String loadbalance,\n                     String version,\n                     Integer timeout,\n                     Integer retries);\n\n    \/**\n     * @Description \u56de\u6536\u8d44\u6e90\n     *\/\n    void destoryCacheWare();\n}\n\n\n\n<\/code><\/pre>\n<p>CacheWareSyncServiceImpl<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.cache.impl;\n\nimport com.google.common.collect.ArrayListMultimap;\nimport com.google.common.collect.Multimap;\nimport com.itheima.shiro.cache.CacheWareService;\nimport com.itheima.shiro.cache.CacheWareSyncService;\nimport com.itheima.shiro.core.bridge.ResourceBridgeService;\nimport com.itheima.shiro.face.ResourceAdapterFace;\nimport com.itheima.shiro.pojo.CacheWare;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.vo.ResourceVo;\nimport lombok.extern.log4j.Log4j2;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.utils.ReferenceConfigCache;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.PreDestroy;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\n\/**\n * @Description\uff1a\n *\/\n@Service(\"cacheWareSyncService\")\n@Log4j2\npublic class CacheWareSyncServiceImpl implements CacheWareSyncService {\n\n    @Value(\"${itheima.resource.systemcode}\")\n    private String systemCode;\n\n    @Autowired\n    ResourceBridgeService resourceBridgeService;\n\n    @Autowired\n    CacheWareService cacheWareService;\n\n    @Autowired\n    private ApplicationConfig applicationConfig;\n\n    @Autowired\n    private RegistryConfig registryConfig;\n\n    private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);\n\n\n    @Override\n    @PostConstruct\n    public void initCacheWare() {\n        executor.scheduleAtFixedRate(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    refreshCacheWare();\n                } catch (Exception e) {\n                    log.error(e.getMessage(), e);\n                }\n            }\n        }, 0, 2, TimeUnit.MINUTES);\n    }\n\n    @Override\n    public void refreshCacheWare()  {\n        List&lt;ResourceVo&gt; resources = resourceBridgeService.findValidResourceVoAll(systemCode);\n        \/\/\u5982\u679c\u5f53\u524d\u7cfb\u7edf\u6ca1\u6709\u8d44\u6e90\uff0c\u5219\u6e05\u7a7a\n        if (CollectionUtils.isEmpty(resources)) {\n            log.warn(\"No apis can be used.\");\n            cacheWareService.clearCacheWare();\n            return;\n        }\n        \/\/\u6784\u5efa\u6267\u884c\u96c6\u5408\n        Multimap&lt;String, CacheWare&gt; cacheWareMaps = ArrayListMultimap.create();\n        for (ResourceVo resource : resources) {\n            if (EmptyUtil.isNullOrEmpty(resource.getServiceName())\n            ||EmptyUtil.isNullOrEmpty(resource.getMethodName())){\n                log.warn(\"{} not found serviceName or methodName\",resources.toString());\n                continue;\n            }\n            CacheWare cacheWare = resourceConvCacheWare(resource);\n            if (!EmptyUtil.isNullOrEmpty(cacheWare)){\n                cacheWareMaps.put(cacheWare.getServiceName()+\":\"+cacheWare.getMethodName(), cacheWare);\n            }\n        }\n        cacheWareService.createCacheWare(cacheWareMaps);\n    }\n\n    @Override\n    public CacheWare resourceConvCacheWare(ResourceVo resource)  {\n        \/\/\u83b7\u5f97\u7c7b\u578b\n        Class&lt;?&gt; serviceClass = null;\n        try {\n            serviceClass = Class.forName(resource.getServiceName());\n        } catch (ClassNotFoundException e) {\n            log.error(\"\u5bb9\u5668\u4e2d\u672a\u53d1\u73b0\uff1a{}\u63a5\u53e3\u7c7b\",resource.getServiceName());\n            return null;\n        }\n        String serviceName = resource.getServiceName().substring(resource.getServiceName().lastIndexOf(\".\")+1).toLowerCase();\n        Method[] methods = serviceClass.getDeclaredMethods();\n        Method methodTarget = null;\n        \/\/\u83b7\u5f97\u65b9\u6cd5\n        for (Method method : methods) {\n            if (method.getName().equals(resource.getMethodName())) {\n                methodTarget = method;\n                break;\n            }\n        }\n        \/\/ \u672a\u5728\u63a5\u53e3\u7c7b\u4e2d\u627e\u5230\u65b9\u6cd5\n        if (methodTarget == null) {\n            log.warn(\"{} not found in {}\", resource.getMethodName(), resource.getServiceName());\n            return null;\n        }\n        \/\/\u83b7\u5f97\u65b9\u6cd5\u4e0a\u7684\u53c2\u6570\n        Class&lt;?&gt;[] methodParamsClasss = methodTarget.getParameterTypes();\n        Class&lt;?&gt; methodParamClasssTarget = null;\n        for (Class&lt;?&gt; methodParamsClass : methodParamsClasss) {\n            if (methodParamsClass.getName().equals(resource.getMethodParam())) {\n                methodParamClasssTarget = methodParamsClass;\n                break;\n            }\n        }\n        \/\/\u521d\u59cb\u5316\u4ee3\u7406\u7c7b\n        Object proxy = initProxy(serviceClass, resource.getLoadbalance(), resource.getDubboVersion(), resource.getTimeout(), resource.getRetries());\n        if (proxy == null) {\n            log.warn(\"{} not found in proxy\", resource.getServiceName());\n            return null;\n        }\n        \/\/\u6784\u5efaCacheWare\u5bf9\u8c61\n        CacheWare cacheWare = CacheWare.builder()\n                .serviceName(serviceName)\n                .methodName(resource.getMethodName())\n                .method(methodTarget)\n                .methodParamsClass(methodParamClasssTarget)\n                .proxy(proxy)\n                .build();\n        return cacheWare;\n    }\n\n    @Override\n    public Object initProxy(Class&lt;?&gt; interfaceClass,\n                            String loadbalance,\n                            String version,\n                            Integer timeout,\n                            Integer retries) {\n        ReferenceConfig&lt;Object&gt; reference = new ReferenceConfig&lt;Object&gt;();\n        reference.setApplication(applicationConfig);\n        reference.setRegistry(registryConfig);\n        reference.setLoadbalance(EmptyUtil.isNullOrEmpty(loadbalance)?\"random\":loadbalance);\n        reference.setInterface(interfaceClass);\n        reference.setVersion(version);\n        reference.setTimeout(EmptyUtil.isNullOrEmpty(timeout)?20000:timeout);\n        reference.setCheck(false);\n        reference.setRetries(EmptyUtil.isNullOrEmpty(retries)?0:retries);\n        ReferenceConfigCache cache = ReferenceConfigCache.getCache();\n        return cache.get(reference);\n    }\n\n    @Override\n    @PreDestroy\n    public void destoryCacheWare() {\n        executor.shutdownNow();\n    }\n}\n\n\n<\/code><\/pre>\n<h5>\u30102.4\u3011\u7f51\u5173\u8d44\u6e90\u89e3\u6790<\/h5>\n<p>\u5176\u4e3b\u8981\u8d1f\u8d23\uff1a<\/p>\n<p>1\u3001\u4f20\u5165\u53c2\u6570\u5904\u7406<\/p>\n<p>2\u3001\u83b7\u5f97\u53ef\u6267\u884c\u7f13\u5b58\u4ed3\u5e93<\/p>\n<p>3\u3001\u6267\u884c\u8fdc\u7a0b\u670d\u52a1<\/p>\n<p>4\u3001\u5904\u7406\u8fd4\u56de\u7ed3\u679c<\/p>\n<pre><code class=\"language-java line-numbers\">package com.itheima.shiro.web;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.itheima.shiro.base.BaseRequest;\nimport com.itheima.shiro.cache.CacheWareService;\nimport com.itheima.shiro.constant.GateWayConstant;\nimport com.itheima.shiro.pojo.CacheWare;\nimport com.itheima.shiro.response.MultiResponse;\nimport com.itheima.shiro.response.PageResponse;\nimport com.itheima.shiro.response.SingleResponse;\nimport com.itheima.shiro.utils.EmptyUtil;\nimport com.itheima.shiro.view.JsonResult;\nimport lombok.extern.log4j.Log4j2;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.websocket.server.PathParam;\nimport java.lang.reflect.Method;\n\n\/**\n * @Description\uff1a\u7f51\u5173\u7edf\u4e00\u5165\u53e3\n *\/\n@Controller\n@Log4j2\npublic class GateWayController {\n\n    @Autowired\n    CacheWareService cacheWareService;\n\n\n    @RequestMapping(value = \"{serviceName}\/{methodName}\", method = RequestMethod.POST)\n    @ResponseBody\n    public JsonResult postGateWay(@PathVariable(\"serviceName\") String serviceName,\n                                  @PathVariable(\"methodName\") String methodName,\n                                  @RequestBody BaseRequest baseRequest) throws Exception {\n        Object datas = baseRequest.getDatas();\n        JsonResult jsonResult = null;\n        if (EmptyUtil.isNullOrEmpty(serviceName)||EmptyUtil.isNullOrEmpty(methodName)){\n            jsonResult = JsonResult.builder()\n                    .result(GateWayConstant.FAIL)\n                    .msg(\"\u53c2\u6570\u7f3a\u5931\")\n                    .code(GateWayConstant.PARAMETERS_MISSING)\n                    .build();\n            return jsonResult;\n        }\n        \/\/1\u3001\u4f20\u5165\u53c2\u6570\u5904\u7406\n        JSONObject datasJson = null;\n        if (!EmptyUtil.isNullOrEmpty(datas)){\n            datasJson = JSONObject.parseObject(JSONObject.toJSONString(datas));\n        }\n        \/\/2\u3001\u83b7\u5f97\u53ef\u6267\u884c\u7f13\u5b58\u4ed3\u5e93\u53ef\u6267\u884c\u5bf9\u8c61\n        CacheWare cacheWare = cacheWareService.queryCacheWare(serviceName, methodName);\n        if (EmptyUtil.isNullOrEmpty(serviceName)||EmptyUtil.isNullOrEmpty(methodName)){\n            jsonResult = JsonResult.builder()\n                    .result(GateWayConstant.FAIL)\n                    .msg(\"\u8bf7\u6c42\u94fe\u63a5\u5f02\u5e38\")\n                    .code(GateWayConstant.URL_MISSING)\n                    .build();\n            return jsonResult;\n        }\n        \/\/3\u3001\u6267\u884c\u8fdc\u7a0b\u670d\u52a1\n        Object proxy = cacheWare.getProxy();\n        Method method = cacheWare.getMethod();\n        Class&lt;?&gt; methodParamsClass = cacheWare.getMethodParamsClass();\n        Object result;\n        if (EmptyUtil.isNullOrEmpty(methodParamsClass)){\n            result = method.invoke(proxy);\n        }else {\n            Object arguments = JSONObject.toJavaObject(datasJson, methodParamsClass);\n            result = method.invoke(proxy,arguments);\n        }\n        \/\/4\u3001\u5904\u7406\u8fd4\u56de\u7ed3\u679c\n        return convResult(result);\n    }\n\n    \/**\n     * @Description \u5904\u7406\u8bf7\u6c42\u7ed3\u679c\n     *\/\n    private JsonResult convResult(Object result) {\n        JsonResult jsonResult = JsonResult.builder()\n                .result(GateWayConstant.SUCCEED)\n                .msg(\"\u76f8\u5e94\u6b63\u5e38\")\n                .code(GateWayConstant.SUCCEED_CODE)\n                .build();\n        if (EmptyUtil.isNullOrEmpty(result)) {\n            jsonResult = JsonResult.builder()\n                    .result(GateWayConstant.FAIL)\n                    .msg(\"\u8fd4\u56de\u7ed3\u679c\u4e3a\u7a7a\")\n                    .code(GateWayConstant.RESULT_ISNULLOREMPTY)\n                    .build();\n            return jsonResult;\n        }\n        if (result instanceof SingleResponse) {\n            BeanUtils.copyProperties(result, jsonResult);\n            @SuppressWarnings(\"rawtypes\")\n            SingleResponse singleResponse = (SingleResponse) result;\n            jsonResult.setDatas(singleResponse.getValue());\n        } else if (result instanceof MultiResponse) {\n            BeanUtils.copyProperties(result, jsonResult);\n            @SuppressWarnings(\"rawtypes\")\n            MultiResponse multiResponse = (MultiResponse) result;\n            jsonResult.setDatas(multiResponse.getValues());\n        } else if (result instanceof PageResponse) {\n            BeanUtils.copyProperties(result, jsonResult);\n            PageResponse pageResponse = (PageResponse)result;\n            jsonResult.setDatas( pageResponse.getValues());\n        } else {\n            jsonResult = JsonResult.builder()\n                    .result(GateWayConstant.FAIL)\n                    .msg(\"\u8fd4\u56de\u7ed3\u679c\u683c\u5f0f\u4e0d\u6b63\u786e\")\n                    .code(GateWayConstant.RESULT_MISSING)\n                    .build();\n            return jsonResult;\n        }\n        return jsonResult;\n    }\n}\n\n<\/code><\/pre>\n<h3>7\u3001shiro-mgt\u7ba1\u7406\u5e73\u53f0<\/h3>\n<h4>\u30101\u3011\u6a21\u5757\u4f9d\u8d56\u5173\u7cfb<\/h4>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582881763304.png\" alt=\"1582881763304\" \/><\/p>\n<h4>\u30102\u3011\u539f\u7406\u5206\u6790<\/h4>\n<p>\u200b       \u901a\u8fc7\u4e0a\u9762\u7684\u6a21\u5757\u4f9d\u8d56\u5173\u7cfb\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u51fa\uff0cshiro-mgt\u7ba1\u7406\u5e73\u53f0\u4e5f\u662f\u4f9d\u8d56springboot-shiro-framework-client\u9879\u76ee\u5b9e\u73b0\u6743\u9650\u7684\u6821\u9a8c\uff0c\u800c\u4ed6\u672c\u8eab\u4e3b\u8981\u662f\u8d1f\u8d23\u5bf9\u89d2\u8272\u3001\u8d44\u6e90\u3001\u7528\u6237\u3001\u8fc7\u6ee4\u5668\u94fe\u7684CRUD\uff0c\u6765\u5b9e\u73b0\u5404\u4e2a\u7f51\u5173\u5e73\u53f0\u7684\u6743\u9650\u63a7\u5236\u3002<\/p>\n<p>\u8d44\u6e90\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582704703769.png\" alt=\"1582704703769\" \/><\/p>\n<p>1\u3001\u5b9a\u4e49\u4e86\u7f51\u5173systemcode\uff0c\u7528\u4ee5\u533a\u5206\u4e0d\u540c\u7f51\u5173\u3001\u7cfb\u7edf<\/p>\n<p>2\u3001\u5b9a\u4e49\u4e86\u8bbf\u95ee\u7684\u8def\u5f84<\/p>\n<p>3\u3001\u5b9a\u4e49\u4e86\u8d44\u6e90\u7684\u552f\u4e00\u6807\u8bc6\uff0c\u4f5c\u4e3a\u8fc7\u6ee4\u5668\u8fc7\u6ee4\u7684\u6807\u8bb0<\/p>\n<p>4\u3001\u5b9a\u4e49dubbo\u670d\u52a1\u7aef\u63a5\u53e3\u7684\u89e3\u6790\u3001\u540c\u65f6\u4e3a\u6bcf\u4e2a\u670d\u52a1\u5b9a\u4e49\uff1a\u8f6e\u8bad\u7b97\u6cd5\u3001\u8d85\u65f6\u65f6\u95f4\u3001\u91cd\u8bd5\u6b21\u6570\u7b49\u53c2\u6570\uff0c\u8fd9\u4e9b\u53c2\u6570\u4f1a\u5728shiro-gateway\u4e2d\u89e3\u6790<\/p>\n<p>\u89d2\u8272\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582704738045.png\" alt=\"1582704738045\" \/><\/p>\n<p>1\u3001\u5b9a\u4e49\u89d2\u8272\u7684\u552f\u4e00\u6807\u8bc6\uff0c\u4f5c\u4e3a\u8fc7\u6ee4\u5668\u8fc7\u6ee4\u7684\u6807\u8bb0<\/p>\n<p>2\u3001\u4e3a\u89d2\u8272\u5b9a\u4e49\u591a\u4e2a\u8d44\u6e90<\/p>\n<p>\u7528\u6237\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582704772681.png\" alt=\"1582704772681\" \/><\/p>\n<p>1\u3001\u7528\u6237\u57fa\u672c\u4fe1\u606f<\/p>\n<p>2\u3001\u4e3a\u7528\u6237\u5b9a\u4e49\u591a\u4e2a\u89d2\u8272<\/p>\n<p>\u8fc7\u6ee4\u5668\u94fe\uff1a<\/p>\n<p><img decoding=\"async\" src=\"\/\/images.weserv.nl\/?url=https:\/\/www.gitee.com\/alan-lou2020\/markdown_doc\/raw\/master\/image\/1582704833744.png\" alt=\"1582704833744\" \/><\/p>\n<p>1\u3001\u4e3a\u6240\u6709\u7cfb\u7edf\u5b9a\u4e49\u7edf\u4e00\u7684\u8fc7\u6ee4\u5668\u94fe\u8def\u7ba1\u7406\uff08\u53ef\u4ee5\u6269\u5c55\uff1a\u6309\u8d44\u6e90\u7c7b\u578b\u90a3\u6837\u4e3a\u6bcf\u4e2a\u7f51\u5173\u7cfb\u7edf\u5b9a\u4e49\u8fc7\u6ee4\u5668\u94fe\uff09<\/p>\n<p>2\u3001\u4fdd\u8bc1\u8fc7\u6ee4\u5668\u5668\u94fe\u7684\u6709\u5e8f\u6027<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u77e5\u8bc6\u70b9 1\u3001\u6743\u9650\u7cfb\u7edf\u7684\u6574\u4f53\u6982\u5ff5 2\u3001shiro\u6743\u9650\u6846\u67b6\u7684\u6838\u5fc3\u7ec4\u4ef6 3\u3001springboot\u4e0bshiro\u7684\u4f7f\u7528  &#8230; <a title=\"shiro\u6743\u9650\u6846\u67b6\" class=\"read-more\" href=\"http:\/\/www.ooboou.com\/?p=506\" aria-label=\"\u9605\u8bfb shiro\u6743\u9650\u6846\u67b6\">\u9605\u8bfb\u66f4\u591a<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[23,24],"class_list":["post-506","post","type-post","status-publish","format-standard","hentry","category-shiro","tag-shiro","tag-24"],"_links":{"self":[{"href":"http:\/\/www.ooboou.com\/index.php?rest_route=\/wp\/v2\/posts\/506","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.ooboou.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.ooboou.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.ooboou.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.ooboou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=506"}],"version-history":[{"count":2,"href":"http:\/\/www.ooboou.com\/index.php?rest_route=\/wp\/v2\/posts\/506\/revisions"}],"predecessor-version":[{"id":513,"href":"http:\/\/www.ooboou.com\/index.php?rest_route=\/wp\/v2\/posts\/506\/revisions\/513"}],"wp:attachment":[{"href":"http:\/\/www.ooboou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=506"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.ooboou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=506"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.ooboou.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}