springboot整合shiro的過(guò)程詳解
什么是 Shiro
Shiro
是一個(gè)強(qiáng)大的簡(jiǎn)單易用的 Java
安全框架,主要用來(lái)更便捷的 認(rèn)證,授權(quán),加密,會(huì)話管理
。Shiro
首要的和最重要的目標(biāo)就是容易使用并且容易理解,通過(guò) Shiro
易于理解的API
,您可以快速、輕松地獲得任何應(yīng)用程序——從最小的移動(dòng)應(yīng)用程序最大的網(wǎng)絡(luò)和企業(yè)應(yīng)用程序
Shiro 架構(gòu)
Shiro 架構(gòu)圖
Authentication
:身份認(rèn)證/
登錄Authorization
:驗(yàn)證權(quán)限,即,驗(yàn)證某個(gè)人是否有做某件事的權(quán)限Session Management
:會(huì)話管理。管理用戶特定的會(huì)話,支持web
與非web
Cryptography
: 加密,保證數(shù)據(jù)安全Caching
:緩存Remember Me
:記住我,即記住登錄狀態(tài),一次登錄后,下次再來(lái)的話不用登錄了
Shiro 工作原理
Shiro
的架構(gòu)有三個(gè)主要概念:Subject
,SecurityManager
和 Realms
Subject
:當(dāng)前參與應(yīng)用安全部分的主角。可以是用戶,可以試第三方服務(wù),可以是cron
任務(wù),或者任何東西。主要指一個(gè)正在與當(dāng)前軟件交互的東西。所有Subject
都需要SecurityManager
,當(dāng)你與Subject
進(jìn)行交互,這些交互行為實(shí)際上被轉(zhuǎn)換為與SecurityManager
的交互SecurityManager
:安全管理器,Shiro
架構(gòu)的核心,它就像Shiro
內(nèi)部所有原件的保護(hù)傘。然而一旦配置了SecurityManager
,SecurityManager
就用到的比較少,開(kāi)發(fā)者大部分時(shí)間都花在Subject
上面。當(dāng)你與Subject
進(jìn)行交互的時(shí)候,實(shí)際上是SecurityManager
在 背后幫你舉起Subject
來(lái)做一些安全操作Realms
:Realms
作為Shiro
和你的應(yīng)用的連接橋,當(dāng)需要與安全數(shù)據(jù)交互的時(shí)候,像用戶賬戶,或者訪問(wèn)控制,Shiro
就從一個(gè)或多個(gè)Realms
中查找。Shiro
提供了一些可以直接使用的Realms
,如果默認(rèn)的Realms
不能滿足你的需求,你也可以定制自己的Realms
Shiro 詳細(xì)架構(gòu)圖
Subject
:與應(yīng)用交互的主體,例如用戶,第三方應(yīng)用等SecurityManager
:shiro
的核心,負(fù)責(zé)整合所有的組件,使他們能夠方便快捷完成某項(xiàng)功能。例如:身份驗(yàn)證,權(quán)限驗(yàn)證等Authenticator
:認(rèn)證器,負(fù)責(zé)主體認(rèn)證的,這是一個(gè)擴(kuò)展點(diǎn),如果用戶覺(jué)得Shiro
默認(rèn)的不好,可以自定義實(shí)現(xiàn);其需要認(rèn)證策略(Authentication Strategy
),即什么情況下算用戶認(rèn)證通過(guò)了。Authorizer
:決定主體是否有權(quán)限進(jìn)行相應(yīng)的操作;即控制著用戶能訪問(wèn)應(yīng)用中的哪些功能SessionManager
:會(huì)話管理。CacheManager
:緩存管理器。創(chuàng)建和管理緩存,為authentication
,authorization
和session
management
提供緩存數(shù)據(jù),避免直接訪問(wèn)數(shù)據(jù)庫(kù),提高效率Cryptography
;密碼模塊,提供加密組件Realms
:可以有1
個(gè)或多個(gè)Realm
,可以認(rèn)為是安全實(shí)體數(shù)據(jù)源,即用于獲取安全實(shí)體的;可以是JDBC
實(shí)現(xiàn),也可以是LDAP
實(shí)現(xiàn),或者內(nèi)存實(shí)現(xiàn)等等;由用戶提供;注意:Shiro
不知道你的用戶/權(quán)限存儲(chǔ)在哪及以何種格式存儲(chǔ);所以我們一般在應(yīng)用中都需要實(shí)現(xiàn)自己的Realm
springboot 整合 shiro
springboot 整合 shiro 思路
項(xiàng)目搭建
主要依賴
<!--thymeleaf 模板引擎--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.4.0</version> </dependency> <!-- thymeleaf 集成 shiro --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
數(shù)據(jù)庫(kù)表設(shè)計(jì)
CREATE TABLE `shiro_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `nickname` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `index_username` (`username`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4; INSERT INTO `shiro_user` VALUES (1, 'lisi', '110110', '李四'); INSERT INTO `shiro_user` VALUES (2, 'zs', '123456', '逆風(fēng)飛翔'); INSERT INTO `shiro_user` VALUES (3, 'jack', '111111', '砥礪奮進(jìn)'); INSERT INTO `shiro_user` VALUES (4, 'Tom', '123123', '靜夜思'); INSERT INTO `shiro_user` VALUES (5, 'nike', '222222', '殺傷力巨大'); CREATE TABLE `shiro_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4; INSERT INTO `shiro_user_role` VALUES (1, 1, 1); INSERT INTO `shiro_user_role` VALUES (2, 2, 3); INSERT INTO `shiro_user_role` VALUES (3, 3, 3); INSERT INTO `shiro_user_role` VALUES (4, 4, 2); CREATE TABLE `shiro_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_code` varchar(255) NOT NULL, `role_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4; INSERT INTO `shiro_role` VALUES (1, '1', '管理員'); INSERT INTO `shiro_role` VALUES (2, '2', '普通一級(jí)用戶'); INSERT INTO `shiro_role` VALUES (3, '3', '普通二級(jí)用戶'); INSERT INTO `shiro_role` VALUES (4, '4', '普通三級(jí)用戶'); CREATE TABLE `shiro_auth_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `auth_id` int(11) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4; INSERT INTO `shiro_auth_role` VALUES (1, 1, 1); INSERT INTO `shiro_auth_role` VALUES (2, 2, 1); INSERT INTO `shiro_auth_role` VALUES (3, 3, 1); INSERT INTO `shiro_auth_role` VALUES (4, 4, 1); INSERT INTO `shiro_auth_role` VALUES (5, 3, 2); INSERT INTO `shiro_auth_role` VALUES (6, 4, 2); INSERT INTO `shiro_auth_role` VALUES (7, 4, 3); INSERT INTO `shiro_auth_role` VALUES (8, 4, 4); INSERT INTO `shiro_auth_role` VALUES (9, 1, 3); CREATE TABLE `shiro_auth` ( `id` int(11) NOT NULL AUTO_INCREMENT, `auth_code` varchar(255) NOT NULL, `auth_name` varchar(255) NOT NULL, `parent_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4; INSERT INTO `shiro_auth` VALUES (1, 'user:add', '添加', 1); INSERT INTO `shiro_auth` VALUES (2, 'user:delete', '刪除', 2); INSERT INTO `shiro_auth` VALUES (3, 'user:update', '更新', 3); INSERT INTO `shiro_auth` VALUES (4, 'user:list', '查看', 4);
實(shí)體類(lèi)
public class User implements Serializable { private Integer id; @NotBlank(message = "賬號(hào)不能為空") private String username; @NotEmpty(message = "密碼不能為空") private String password; private String nickname; // set/get方法省略 } public class Role { private Integer id; private String roleCode; private String roleName; // set/get方法省略 } public class Auth { private Integer id; private String authCode; private String authName; private Integer parentId; // set/get方法省略 }
自定義 Realm
realm
是 shiro
進(jìn)行登錄認(rèn)證,權(quán)限,角色校驗(yàn)的關(guān)鍵,我們需要重寫(xiě)里面的方法
@Component @Slf4j public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; // 授權(quán),權(quán)限操作 @Override protected AuthorizationInfo doGetAuthorizationInfo(@NotNull PrincipalCollection principals) { log.info("------進(jìn)入授權(quán)操作了------"); User user = (User) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 通過(guò)賬號(hào)來(lái)查詢相應(yīng)的角色,權(quán)限數(shù)據(jù) List<AuthAndRoleVO> authAndRoleVOS = userService.selectAuthAndRole(user.getUsername()); authAndRoleVOS.forEach(item -> { log.info("查詢到的權(quán)限,角色:" + item.toString()); String roleName = item.getRoleName(); String authCode = item.getAuthCode(); info.addStringPermission(authCode); info.addRole(roleName); }); return info; } // 認(rèn)證操作 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { log.info("------進(jìn)入認(rèn)證操作了------"); // 拿到UsernamePasswordToken,它里面有用戶名,密碼數(shù)據(jù) UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; // 查詢數(shù)據(jù)庫(kù) User user = userService.selectOne(usernamePasswordToken.getUsername(), String.valueOf(usernamePasswordToken.getPassword())); if (user == null) { return null; } return new SimpleAuthenticationInfo(user, token.getCredentials(), getName()); } }
- 這里
ORM
持久層不再贅述,用mybatis
或jpa
等都可以 doGetAuthorizationInfo()
: 權(quán)限認(rèn)證。即登錄過(guò)后,每個(gè)用戶的身份不一樣,對(duì)應(yīng)的所能看的頁(yè)面也不一樣,也就是擁有的權(quán)限也不一樣doGetAuthenticationInfo()
:身份認(rèn)證。即登錄通過(guò)賬號(hào)和密碼驗(yàn)證登陸人的身份信息
shiro 的配置類(lèi)
@Configuration public class ShiroConfig { /** * 安全管理器 */ @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(userRealm); return defaultWebSecurityManager; } /** * thymeleaf模板引擎中使用shiro標(biāo)簽時(shí),要用到 */ @Bean public ShiroDialect getShiroDialect() { return new ShiroDialect(); } @Bean public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); // 設(shè)置登錄頁(yè)面url shiroFilterFactoryBean.setLoginUrl("/user/login"); shiroFilterFactoryBean.setSuccessUrl("/user/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauthorized"); // 注意此處使用的是LinkedHashMap是有順序的,shiro會(huì)按從上到下的順序匹配驗(yàn)證,匹配了就不再繼續(xù)驗(yàn)證 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 靜態(tài)資源放行 filterChainDefinitionMap.put("/layer/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/jquery/**", "anon"); // add.html頁(yè)面放行 filterChainDefinitionMap.put("/user/add", "anon"); // update.html必須認(rèn)證 filterChainDefinitionMap.put("/user/update", "authc"); // index.html必須認(rèn)證 filterChainDefinitionMap.put("/user/index", "authc"); // 設(shè)置授權(quán),只有user:add權(quán)限的才能請(qǐng)求/user/add這個(gè)url filterChainDefinitionMap.put("/user/add", "perms[user:add]"); filterChainDefinitionMap.put("/user/update", "perms[user:update]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } }
ShiroFilterFactoryBean 過(guò)濾器鏈配置中的 url 匹配規(guī)則
- ?:匹配一個(gè)字符,如 /admin?,將匹配 /admin1、/admin2,但不匹配 /admin
- *:匹配零個(gè)或多個(gè)字符串,如 /admin* ,將匹配 /admin、/admin123,但不匹配 /admin/1
- **:匹配路徑中的零個(gè)或多個(gè)路徑,如 /admin/**,將匹配 /admin/a、/admin/a/b
ShiroFilterFactoryBean 過(guò)濾器
- anon:匿名過(guò)濾器,無(wú)需認(rèn)證就可以訪問(wèn)。例:/statics/**= anon 表示 statics 目錄下所有資源都能訪問(wèn)
- authc:必須認(rèn)證了才能訪問(wèn),否則跳轉(zhuǎn)到登錄頁(yè)面。例:/unauthor.jsp= authc 如果用戶沒(méi)有登錄就訪問(wèn) unauthor.jsp,則直接跳轉(zhuǎn)到登錄頁(yè)面
- user:必須通過(guò)記住我功能通過(guò)或認(rèn)證通過(guò)才能訪問(wèn)
- perms:擁有對(duì)某個(gè)資源的權(quán)限才能訪問(wèn)。例:/statics/** = perms["user:add:*,user:modify:*"] 表示訪問(wèn) statics 目錄下的資源時(shí)只有新增和修改的權(quán)限
- roles:擁有某個(gè)角色權(quán)限才能訪問(wèn)。例:/welcom.jsp = roles[admin] 表示訪問(wèn) welcom.jsp 頁(yè)面時(shí)會(huì)檢查是否擁有 admin 角色
ShiroFilterFactoryBean 過(guò)濾器分類(lèi)
- 認(rèn)證過(guò)濾器:anon、authcBasic、auchc、user、logout
- 授權(quán)過(guò)濾器:perms、roles、ssl、rest、port
前端頁(yè)面
登錄頁(yè)面 login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登錄</title> <link rel="shortcut icon" type="image/x-icon" th:href="@{/img/favicon.ico}" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <form action="" method="post"> <p> 賬號(hào): <label><input type="text" class="username" name="username"></label> </p> <p> 密碼: <label><input type="text" class="password" name="password"></label> </p> <p> <label><input id="checkbox1" type="checkbox" name="rememberMe"></label>記住我 </p> <p><button type="button" class="loginBtn">登錄</button></p> </form> </body> <script type="text/javascript" th:src="@{/jquery/jquery-3.3.1.min.js}"></script> <script type="text/javascript" th:src="@{/layer/layer.js}"></script><!--layui的彈出層--> <script type="text/javascript"> $(document).ready(function () { $('.loginBtn').on('click', function () { // 登錄按鈕 const username = $('.username').val(); const password = $('.password').val(); $.ajax({// 用戶登錄 type: 'post', url: '/user/doLogin', dataType: 'json', data: ({ 'username': username, 'password': password }), success: function (resp) { console.log(resp); if (resp.code !== 200) { layer.msg(resp.message, function () {// layui的彈窗 }); } else if (resp.code === 200) { window.location.+ resp.action; } }, error: function () {// 此處添加錯(cuò)誤處理 layer.open({ title: '提示信息', content: '后臺(tái)訪問(wèn)錯(cuò)誤,請(qǐng)聯(lián)系管理員', skin: 'layui-layer-molv', icon: 0 }); } }); }); }); </script> </html>
首頁(yè)頁(yè)面 index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首頁(yè)</title> <link rel="shortcut icon" type="image/x-icon" th:href="@{/img/favicon.ico}" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <h1>首頁(yè)</h1> <a th:href="@{/user/add}" rel="external nofollow" >add</a> | <a th:href="@{/user/update}" rel="external nofollow" >update</a><br> <a th:href="@{/user/logout}" rel="external nofollow" rel="external nofollow" rel="external nofollow" >退出登錄</a> </body> </html>
添加頁(yè)面 add.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>add</title> <link rel="shortcut icon" type="image/x-icon" th:href="@{/img/favicon.ico}" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <h1>add</h1><br> <a th:href="@{/user/logout}" rel="external nofollow" rel="external nofollow" rel="external nofollow" >退出登錄</a> </body> </html>
更新頁(yè)面 update.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>update</title> <link rel="shortcut icon" type="image/x-icon" th:href="@{/img/favicon.ico}" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <h1>update</h1><br> <a th:href="@{/user/logout}" rel="external nofollow" rel="external nofollow" rel="external nofollow" >退出登錄</a> </body> </html>
未授權(quán)頁(yè)面 unauthorized.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>未授權(quán)</title> <link rel="shortcut icon" type="image/x-icon" th:href="@{/img/favicon.ico}" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <p1>未授權(quán),無(wú)法訪問(wèn)此頁(yè)面</p1></br> <a th:href="@{/user/index}" rel="external nofollow" >回到上一頁(yè)</a> </body> </html>
controller 控制器
鑒于文章篇幅,這里只展示主要的邏輯代碼
@Controller @RequestMapping(path = "/user") @Slf4j public class UserController { @GetMapping(path = "/login") public String login() { return "login"; } @GetMapping(path = "/index") public String index() { return "index"; } @GetMapping(path = "/add") public String add() { return "add"; } @GetMapping(path = "/update") public String update() { return "update"; } // 未授權(quán)頁(yè)面 @GetMapping(path = "/unauthorized") public String unauthorized() { return "unauthorized"; } // 用戶登錄 @PostMapping(path = "/doLogin") @ResponseBody public ResultMap doLogin(@NotNull @Valid User user, @NotNull BindingResult bindingResult) { // ------參數(shù)校驗(yàn)------ if (bindingResult.hasErrors()) { String message = Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage(); log.info("校驗(yàn)的message信息為:" + message); return new ResultMap().fail().message(message); } // 將用戶名,密碼交給shiro UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); String msg; try { // shiro幫我們匹配密碼什么的,我們只需要把東西傳給它,它會(huì)根據(jù)我們?cè)赨serRealm里認(rèn)證方法設(shè)置的來(lái)驗(yàn)證 Subject subject = SecurityUtils.getSubject(); subject.login(token); return new ResultMap().success().action("/user/index"); } catch (AuthenticationException e) { if (e instanceof IncorrectCredentialsException) { msg = "密碼錯(cuò)誤"; } else if (e instanceof LockedAccountException) { msg = "用戶被禁用"; } else if (e instanceof UnknownAccountException) { msg = "用戶不存在"; } else { msg = "用戶認(rèn)證失敗"; } } return new ResultMap().error().message(msg); } // 用戶退出登錄 @GetMapping(path = "/logout") public String logout() { SecurityUtils.getSubject().logout(); return "login"; } }
shiro 注解
在 contrller 的這些方法中,也可以使用 shiro 提供的一些注解來(lái)校驗(yàn)用戶,認(rèn)證用戶。不過(guò)個(gè)人認(rèn)為使用這些注解有點(diǎn)麻煩(因?yàn)橛行┳⒔鈺?huì)拋出異常,然后再 controller 層還要捕獲異常),所以我在 ShiroConfig 配置類(lèi)中進(jìn)行了配置
- @RequiresAuthentication:表示當(dāng)前 Subject 已經(jīng)通過(guò) login 進(jìn)行了身份驗(yàn)證;即 Subject.isAuthenticated() 返回 true
- @RequiresUser:表示當(dāng)前 Subject 已經(jīng)通過(guò)身份驗(yàn)證或者通過(guò)記住我進(jìn)行登錄的
- @RequiresGuest:表示當(dāng)前 Subject 沒(méi)有身份驗(yàn)證或通過(guò)記住我登錄過(guò),即是游客身份
- @RequiresRoles(value={“admin”, “user”}, logical= Logical.AND):表示當(dāng)前 Subject 需要角色 admin 和 user。如果當(dāng)前 Subject 不同時(shí) 擁有所有指定角色,則方法不會(huì)執(zhí)行還會(huì)拋出 AuthorizationException 異常
- @RequiresPermissions(value={“user:a”, “user:b”}, logical= Logical.OR):表示當(dāng)前 Subject 需要權(quán)限 user:a 或 user:b。如果當(dāng)前 Subject 不具有這樣的權(quán)限,則方法不會(huì)被執(zhí)行
測(cè)試
啟動(dòng)項(xiàng)目,首先進(jìn)入登錄頁(yè)面 login.html,如下
我們分別以數(shù)據(jù)庫(kù)中的 {jack,111111} 和 {Tom,123123} 賬號(hào)與密碼進(jìn)行測(cè)試
測(cè)試一
首先使用 {jack,111111} 來(lái)進(jìn)行登錄,如下
進(jìn)入首頁(yè)頁(yè)面,如下
我們?cè)诮又榭纯刂婆_(tái)日志,如下
我們看到首頁(yè)頁(yè)面有兩個(gè)超鏈接頁(yè)面,以用戶 jack 的身份分別進(jìn)入兩個(gè)頁(yè)面。首先進(jìn)入 add.html 頁(yè)面,如下
說(shuō)明用戶 jack 擁有訪問(wèn) add.html 的權(quán)限,此時(shí)在查看控制臺(tái)日志,如下
注意查看用戶 jack 的數(shù)據(jù),他的權(quán)限只有 user/add 和 user/list,是沒(méi)有 user/update 權(quán)限的,也就是沒(méi)有權(quán)限訪問(wèn) update.html 頁(yè)面的??梢则?yàn)證,我們?cè)僖杂脩?jack 的身份進(jìn)入 update.html 頁(yè)面,如下
關(guān)于測(cè)試,到此為止。當(dāng)然,依然可以使用其他的數(shù)據(jù)在進(jìn)行測(cè)試
小結(jié)
shiro 最為關(guān)鍵的就是 realm 了,繼承 AuthorizingRealm,然后重寫(xiě)兩個(gè)方法
- doGetAuthorizationInfo(): 權(quán)限認(rèn)證。即登錄過(guò)后,每個(gè)用戶的身份不一樣,對(duì)應(yīng)的所能看的頁(yè)面也不一樣,也就是擁有的權(quán)限也不一樣
- doGetAuthenticationInfo():身份認(rèn)證。即登錄通過(guò)賬號(hào)和密碼驗(yàn)證登陸人的身份信息
在 controller 中的核心登錄操作,就是將前端頁(yè)面用戶的登錄數(shù)據(jù)(如賬號(hào),密碼)交給 UsernamePasswordToken,然后使用當(dāng)前的 Subject 對(duì)象調(diào)用 login(token) 方法即可,如下
// 將用戶名,密碼交給shiro UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); // shiro幫我們匹配密碼什么的,我們只需要把東西傳給它,它會(huì)根據(jù)我們?cè)赨serRealm里認(rèn)證方法設(shè)置的來(lái)驗(yàn)證 Subject subject = SecurityUtils.getSubject(); subject.login(token);
到此這篇關(guān)于springboot整合shiro的文章就介紹到這了,更多相關(guān)springboot整合shiro內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot訪問(wèn)HTML過(guò)程詳解
這篇文章主要詳細(xì)介紹了SpringBoot訪問(wèn)HTML的全過(guò)程,文章中有詳細(xì)的代碼和圖片講解,感興趣的同學(xué)可以參考一下2023-04-04java項(xiàng)目實(shí)現(xiàn)猜拳小游戲
這篇文章主要為大家詳細(xì)介紹了java項(xiàng)目實(shí)現(xiàn)猜拳小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05關(guān)于ZooKeeper的會(huì)話機(jī)制Session解讀
這篇文章主要介紹了關(guān)于ZooKeeper的會(huì)話機(jī)制Session解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問(wèn)題
這篇文章主要介紹了自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Java利用讀寫(xiě)的方式實(shí)現(xiàn)音頻播放代碼實(shí)例
這篇文章主要介紹了Java利用讀寫(xiě)的方式實(shí)現(xiàn)音頻播放代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11SpringBoot?將配置文件掛到?jar?包外面的操作方法
在 SpringBoot 中,可以將配置文件放在 jar 包外面,這樣可以方便地修改配置而不需要重新打包和部署,這篇文章主要介紹了SpringBoot?如何將配置文件掛到?jar?包外面,需要的朋友可以參考下2023-03-03Spring Cloud根據(jù)服務(wù)名獲取服務(wù)的ip端口問(wèn)題
這篇文章主要介紹了Spring Cloud根據(jù)服務(wù)名獲取服務(wù)的ip端口,本篇示例我就以Nacos注冊(cè)中心為例了,下面是我注冊(cè)的兩個(gè)服務(wù),需要的朋友可以參考下2022-09-09