詳解如何在項(xiàng)目中應(yīng)用SpringSecurity權(quán)限控制
要進(jìn)行認(rèn)證和授權(quán)需要前面課程中提到的權(quán)限模型涉及的7張表支撐,因?yàn)橛脩粜畔?、?quán)限信息、菜單信息、角色信息、關(guān)聯(lián)信息等都保存在這7張表中,也就是這些表中的數(shù)據(jù)是我們進(jìn)行認(rèn)證和授權(quán)的依據(jù)。所以在真正進(jìn)行認(rèn)證和授權(quán)之前需要對(duì)這些數(shù)據(jù)進(jìn)行管理,即我們需要開(kāi)發(fā)如下一些功能:
1、權(quán)限數(shù)據(jù)管理(增刪改查)
2、菜單數(shù)據(jù)管理(增刪改查)
3、角色數(shù)據(jù)管理(增刪改查、角色關(guān)聯(lián)權(quán)限、角色關(guān)聯(lián)菜單)
4、用戶數(shù)據(jù)管理(增刪改查、用戶關(guān)聯(lián)角色)
數(shù)據(jù)庫(kù)數(shù)據(jù)實(shí)現(xiàn)導(dǎo)入,簡(jiǎn)化上面的4步步驟
DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `birthday` date DEFAULT NULL, `gender` varchar(1) DEFAULT NULL, `username` varchar(32) DEFAULT NULL, `password` varchar(256) DEFAULT NULL, `remark` varchar(32) DEFAULT NULL, `station` varchar(1) DEFAULT NULL, `telephone` varchar(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_user -- ---------------------------- INSERT INTO `t_user` VALUES ('1', null, null, 'admin', '$2a$10$u/BcsUUqZNWUxdmDhbnoeeobJy6IBsL1Gn/S0dMxI2RbSgnMKJ.4a', null, null, null); INSERT INTO `t_user` VALUES ('2', null, null, 'xiaoming', '$2a$10$3xW2nBjwBM3rx1LoYprVsemNri5bvxeOd/QfmO7UDFQhW2HRHLi.C', null, null, null); INSERT INTO `t_user` VALUES ('3', null, null, 'test', '$2a$10$zYJRscVUgHX1wqwu90WereuTmIg6h/JGirGG4SWBsZ60wVPCgtF8W', null, null, null); DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `user_id` int(11) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`role_id`), KEY `FK_Reference_8` (`role_id`), CONSTRAINT `FK_Reference_7` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`), CONSTRAINT `FK_Reference_8` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_user_role -- ---------------------------- INSERT INTO `t_user_role` VALUES ('1', '1'); INSERT INTO `t_user_role` VALUES ('2', '2'); DROP TABLE IF EXISTS `t_permission`; CREATE TABLE `t_permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `keyword` varchar(64) DEFAULT NULL, `description` varchar(128) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_permission -- ---------------------------- INSERT INTO `t_permission` VALUES ('1', '新增檢查項(xiàng)', 'CHECKITEM_ADD', null); INSERT INTO `t_permission` VALUES ('2', '刪除檢查項(xiàng)', 'CHECKITEM_DELETE', null); INSERT INTO `t_permission` VALUES ('3', '編輯檢查項(xiàng)', 'CHECKITEM_EDIT', null); INSERT INTO `t_permission` VALUES ('4', '查詢檢查項(xiàng)', 'CHECKITEM_QUERY', null); INSERT INTO `t_permission` VALUES ('5', '新增檢查組', 'CHECKGROUP_ADD', null); INSERT INTO `t_permission` VALUES ('6', '刪除檢查組', 'CHECKGROUP_DELETE', null); INSERT INTO `t_permission` VALUES ('7', '編輯檢查組', 'CHECKGROUP_EDIT', null); INSERT INTO `t_permission` VALUES ('8', '查詢檢查組', 'CHECKGROUP_QUERY', null); INSERT INTO `t_permission` VALUES ('9', '新增套餐', 'SETMEAL_ADD', null); INSERT INTO `t_permission` VALUES ('10', '刪除套餐', 'SETMEAL_DELETE', null); INSERT INTO `t_permission` VALUES ('11', '編輯套餐', 'SETMEAL_EDIT', null); INSERT INTO `t_permission` VALUES ('12', '查詢套餐', 'SETMEAL_QUERY', null); INSERT INTO `t_permission` VALUES ('13', '預(yù)約設(shè)置', 'ORDERSETTING', null); INSERT INTO `t_permission` VALUES ('14', '查看統(tǒng)計(jì)報(bào)表', 'REPORT_VIEW', null); INSERT INTO `t_permission` VALUES ('15', '新增菜單', 'MENU_ADD', null); INSERT INTO `t_permission` VALUES ('16', '刪除菜單', 'MENU_DELETE', null); INSERT INTO `t_permission` VALUES ('17', '編輯菜單', 'MENU_EDIT', null); INSERT INTO `t_permission` VALUES ('18', '查詢菜單', 'MENU_QUERY', null); INSERT INTO `t_permission` VALUES ('19', '新增角色', 'ROLE_ADD', null); INSERT INTO `t_permission` VALUES ('20', '刪除角色', 'ROLE_DELETE', null); INSERT INTO `t_permission` VALUES ('21', '編輯角色', 'ROLE_EDIT', null); INSERT INTO `t_permission` VALUES ('22', '查詢角色', 'ROLE_QUERY', null); INSERT INTO `t_permission` VALUES ('23', '新增用戶', 'USER_ADD', null); INSERT INTO `t_permission` VALUES ('24', '刪除用戶', 'USER_DELETE', null); INSERT INTO `t_permission` VALUES ('25', '編輯用戶', 'USER_EDIT', null); INSERT INTO `t_permission` VALUES ('26', '查詢用戶', 'USER_QUERY', null); -- ---------------------------- -- Table structure for `t_role` -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `keyword` varchar(64) DEFAULT NULL, `description` varchar(128) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_role -- ---------------------------- INSERT INTO `t_role` VALUES ('1', '系統(tǒng)管理員', 'ROLE_ADMIN', null); INSERT INTO `t_role` VALUES ('2', '健康管理師', 'ROLE_HEALTH_MANAGER', null); -- ---------------------------- -- Table structure for `t_role_menu` -- ---------------------------- DROP TABLE IF EXISTS `t_role_menu`; CREATE TABLE `t_role_menu` ( `role_id` int(11) NOT NULL, `menu_id` int(11) NOT NULL, PRIMARY KEY (`role_id`,`menu_id`), KEY `FK_Reference_10` (`menu_id`), CONSTRAINT `FK_Reference_10` FOREIGN KEY (`menu_id`) REFERENCES `t_menu` (`id`), CONSTRAINT `FK_Reference_9` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_role_menu -- ---------------------------- INSERT INTO `t_role_menu` VALUES ('1', '1'); INSERT INTO `t_role_menu` VALUES ('2', '1'); INSERT INTO `t_role_menu` VALUES ('1', '2'); INSERT INTO `t_role_menu` VALUES ('2', '2'); INSERT INTO `t_role_menu` VALUES ('1', '3'); INSERT INTO `t_role_menu` VALUES ('2', '3'); INSERT INTO `t_role_menu` VALUES ('1', '4'); INSERT INTO `t_role_menu` VALUES ('2', '4'); INSERT INTO `t_role_menu` VALUES ('1', '5'); INSERT INTO `t_role_menu` VALUES ('1', '6'); INSERT INTO `t_role_menu` VALUES ('1', '7'); INSERT INTO `t_role_menu` VALUES ('1', '8'); INSERT INTO `t_role_menu` VALUES ('1', '9'); INSERT INTO `t_role_menu` VALUES ('1', '10'); INSERT INTO `t_role_menu` VALUES ('1', '11'); INSERT INTO `t_role_menu` VALUES ('1', '12'); INSERT INTO `t_role_menu` VALUES ('1', '13'); INSERT INTO `t_role_menu` VALUES ('1', '14'); INSERT INTO `t_role_menu` VALUES ('1', '15'); INSERT INTO `t_role_menu` VALUES ('1', '16'); INSERT INTO `t_role_menu` VALUES ('1', '17'); INSERT INTO `t_role_menu` VALUES ('1', '18'); INSERT INTO `t_role_menu` VALUES ('1', '19'); INSERT INTO `t_role_menu` VALUES ('1', '20'); INSERT INTO `t_role_menu` VALUES ('1', '21'); -- ---------------------------- -- Table structure for `t_role_permission` -- ---------------------------- DROP TABLE IF EXISTS `t_role_permission`; CREATE TABLE `t_role_permission` ( `role_id` int(11) NOT NULL, `permission_id` int(11) NOT NULL, PRIMARY KEY (`role_id`,`permission_id`), KEY `FK_Reference_12` (`permission_id`), CONSTRAINT `FK_Reference_11` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`), CONSTRAINT `FK_Reference_12` FOREIGN KEY (`permission_id`) REFERENCES `t_permission` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_role_permission -- ---------------------------- INSERT INTO `t_role_permission` VALUES ('1', '1'); INSERT INTO `t_role_permission` VALUES ('2', '1'); INSERT INTO `t_role_permission` VALUES ('1', '2'); INSERT INTO `t_role_permission` VALUES ('2', '2'); INSERT INTO `t_role_permission` VALUES ('1', '3'); INSERT INTO `t_role_permission` VALUES ('2', '3'); INSERT INTO `t_role_permission` VALUES ('1', '4'); INSERT INTO `t_role_permission` VALUES ('2', '4'); INSERT INTO `t_role_permission` VALUES ('1', '5'); INSERT INTO `t_role_permission` VALUES ('2', '5'); INSERT INTO `t_role_permission` VALUES ('1', '6'); INSERT INTO `t_role_permission` VALUES ('2', '6'); INSERT INTO `t_role_permission` VALUES ('1', '7'); INSERT INTO `t_role_permission` VALUES ('2', '7'); INSERT INTO `t_role_permission` VALUES ('1', '8'); INSERT INTO `t_role_permission` VALUES ('2', '8'); INSERT INTO `t_role_permission` VALUES ('1', '9'); INSERT INTO `t_role_permission` VALUES ('2', '9'); INSERT INTO `t_role_permission` VALUES ('1', '10'); INSERT INTO `t_role_permission` VALUES ('2', '10'); INSERT INTO `t_role_permission` VALUES ('1', '11'); INSERT INTO `t_role_permission` VALUES ('2', '11'); INSERT INTO `t_role_permission` VALUES ('1', '12'); INSERT INTO `t_role_permission` VALUES ('2', '12'); INSERT INTO `t_role_permission` VALUES ('1', '13'); INSERT INTO `t_role_permission` VALUES ('2', '13'); INSERT INTO `t_role_permission` VALUES ('1', '14'); INSERT INTO `t_role_permission` VALUES ('2', '14'); INSERT INTO `t_role_permission` VALUES ('1', '15'); INSERT INTO `t_role_permission` VALUES ('1', '16'); INSERT INTO `t_role_permission` VALUES ('1', '17'); INSERT INTO `t_role_permission` VALUES ('1', '18'); INSERT INTO `t_role_permission` VALUES ('1', '19'); INSERT INTO `t_role_permission` VALUES ('1', '20'); INSERT INTO `t_role_permission` VALUES ('1', '21'); INSERT INTO `t_role_permission` VALUES ('1', '22'); INSERT INTO `t_role_permission` VALUES ('1', '23'); INSERT INTO `t_role_permission` VALUES ('1', '24'); INSERT INTO `t_role_permission` VALUES ('1', '25'); INSERT INTO `t_role_permission` VALUES ('1', '26');
1、Spring Security環(huán)境準(zhǔn)備
pom.xml中導(dǎo)入Spring Security的maven坐標(biāo),目前版本使用的是
5.0.5.RELEASE
,版本如果過(guò)高可能就會(huì)導(dǎo)致不同的報(bào)錯(cuò)
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.security.version}</version> </dependency>
1.1、在health_backend工程的web.xml文件中配置用于整合Spring Security框架的過(guò)濾器DelegatingFilterProxy
<!--委派過(guò)濾器,用于整合其他框架--> <filter> <!--整合spring security時(shí),此過(guò)濾器的名稱固定springSecurityFilterChain--> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <!--注意區(qū)分放置的位置,有嚴(yán)格的先后順序--> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、實(shí)現(xiàn)認(rèn)證和授權(quán)
在health_backend工程中按照Spring Security框架要求提供SpringSecurityUserService,并且實(shí)現(xiàn)UserDetailsService接口
package com.zcl.security; import com.alibaba.dubbo.config.annotation.Reference; import com.itheima.pojo.Permission; import com.itheima.pojo.Role; import com.itheima.pojo.User; import com.zcl.service.UserService; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * 項(xiàng)目名稱:health_parent * 描述:SpringSecurity實(shí)現(xiàn)認(rèn)證和授權(quán) * * @author zhong * @date 2022-06-24 12:09 */ @Component public class SpringSecurityUserService implements UserDetailsService { /** * 使用dubbo網(wǎng)絡(luò)遠(yuǎn)程調(diào)用服務(wù)提供方查詢用戶數(shù)據(jù) */ @Reference private UserService userService; /** * 根據(jù)用戶名查詢數(shù)據(jù)庫(kù)獲取用戶信息 * @param username * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.findByUsername(username); if(user == null) {return null;}; List<GrantedAuthority> list = new ArrayList<>(); // 動(dòng)態(tài)為當(dāng)前用戶授權(quán) Set<Role> roles = user.getRoles(); // 遍歷角色集合,為用戶授予角色 for (Role role : roles) { // 為用戶授予角色 list.add(new SimpleGrantedAuthority(role.getKeyword())); // 獲取權(quán)限 Set<Permission> permissions = role.getPermissions(); // 遍歷權(quán)限,為角色授權(quán) for (Permission permission : permissions) { list.add(new SimpleGrantedAuthority(permission.getKeyword())); } } /* * 將密碼交由框架比對(duì) * 參數(shù)一:賬號(hào) * 參數(shù)二:查詢數(shù)據(jù)庫(kù)的密碼,已加密的 * 參數(shù)三:用戶角色所具有的權(quán)限 */ org.springframework.security.core.userdetails.User UserSecurity = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list); return UserSecurity; } }
創(chuàng)建遠(yuǎn)程調(diào)用的UserService
接口
public interface UserService { /** * 根據(jù)登錄名查詢用戶數(shù)據(jù) * @param username * @return */ User findByUsername(String username); }
創(chuàng)建接口實(shí)現(xiàn)類
需要注入數(shù)據(jù)訪問(wèn)層來(lái)完成數(shù)據(jù)的查詢,用戶、角色、權(quán)限各自創(chuàng)建一個(gè)dao和映射文件
package com.zcl.service.impl; import com.alibaba.dubbo.config.annotation.Service; import com.itheima.pojo.Permission; import com.itheima.pojo.Role; import com.itheima.pojo.User; import com.zcl.dao.PermissionDao; import com.zcl.dao.RoleDao; import com.zcl.dao.UserDao; import com.zcl.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import java.util.Set; /** * 項(xiàng)目名稱:health_parent * 描述:用戶服務(wù)實(shí)現(xiàn)類 * * @author zhong * @date 2022-06-24 14:35 */ @Service(interfaceClass = UserService.class) @Transactional public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Autowired private RoleDao roleDao; @Autowired private PermissionDao permissionDao; /** * 根據(jù)用戶名稱查詢用戶角色信息和關(guān)聯(lián)的角色信息,同時(shí)需要查詢角色關(guān)聯(lián)的權(quán)限信息 * @param username * @return */ @Override public User findByUsername(String username) { // 1、查詢用戶基本信息,不包含用戶角色信息 User user = userDao.findByUsername(username); if(user == null){ return null; } // 2、根據(jù)用戶查詢的用戶id查詢角色信息 Integer userId = user.getId(); Set<Role> roles = roleDao.findByUserId(userId); // 3、根據(jù)角色來(lái)查詢權(quán)限 for (Role role : roles) { Integer roleId = role.getId(); Set<Permission> permissions = permissionDao.findByRoleId(roleId); // 讓角色關(guān)聯(lián)權(quán)限 role.setPermissions(permissions); } // 讓用還關(guān)聯(lián)角色 user.setRoles(roles); return user; } }
創(chuàng)建【用戶、角色、權(quán)限】數(shù)據(jù)訪問(wèn)層接口
注意:這三個(gè)接口都不是在同一個(gè)類中的,而是各自獨(dú)立的接口類,不要寫(xiě)在一起
public interface UserDao { User findByUsername(String username); } public interface RoleDao { Set<Role> findByUserId(Integer userId); } public interface PermissionDao { Set<Permission> findByRoleId(Integer roleId); }
查詢用戶的Mapper映射文件查詢數(shù)據(jù)
映射文件創(chuàng)建在
resources
文件下,注意的是需要與dao
接口的包一致
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zcl.dao.UserDao"> <!--根據(jù)用戶名稱查詢用戶信息--> <select id="findByUsername" parameterType="string" resultType="com.itheima.pojo.User"> select * from t_user where username = #{username} </select> </mapper>
根據(jù)用戶id查詢角色信息Mapper映射文件查詢
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zcl.dao.RoleDao"> <!--根據(jù)用戶id查詢角色信息--> <select id="findByUserId" resultType="com.itheima.pojo.Role" parameterType="int"> select r.* from t_role r,t_user_role ur where r.id = ur.role_id and ur.user_id = #{user_id} </select> </mapper>
根據(jù)角色id查詢角色權(quán)限Mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zcl.dao.PermissionDao"> <!--根據(jù)角色id查詢權(quán)限--> <select id="findByRoleId" resultType="com.itheima.pojo.Permission" parameterType="int"> select p.* from t_permission p,t_role_permission rp where p.id = rp.permission_id and rp.role_id = ${role_id} </select> </mapper>
修改dubbo的批量掃描
原因:默認(rèn)配置的dubbo掃描的是Controller包下的,所以我們創(chuàng)建了一個(gè)新的包server用于存放權(quán)限實(shí)現(xiàn)類,而實(shí)現(xiàn)類剛好也是使用dubbo來(lái)遠(yuǎn)程調(diào)用接口查詢數(shù)據(jù)庫(kù)的,需要使用到dubbo就需要被掃描到
<!--批量掃描--> <dubbo:annotation package="com.zcl" />
創(chuàng)建springSecurity.xml配置文件
與上一篇的入門(mén)案例不同的是,
SpringSecurityUserService
認(rèn)證提供者不需要在配置文件里面創(chuàng)建bean交給spring容器了,因?yàn)樵陬惖纳厦嬉呀?jīng)使用@Component
創(chuàng)建,在spring容器中已經(jīng)有了,通過(guò)小寫(xiě)字母即可引用如果引用認(rèn)證類報(bào)紅就不需要管,影響不到程序,只是IDEA的檢測(cè)問(wèn)題
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--配置哪些資源匿名可以訪問(wèn)的資源(不登錄頁(yè)可以訪問(wèn))--> <security:http security="none" pattern="/login.html"></security:http> <security:http security="none" pattern="/css/**"></security:http> <security:http security="none" pattern="/js/**"></security:http> <security:http security="none" pattern="/img/**"></security:http> <security:http security="none" pattern="/plugins/**"></security:http> <!-- http:用于定義相關(guān)權(quán)限控制 auto-config:是否自動(dòng)配置 設(shè)置為true時(shí)框架會(huì)提供默認(rèn)的一些配置,例如提供默認(rèn)的登錄頁(yè)面、登出處理等 設(shè)置為false時(shí)需要顯示提供登錄表單配置,否則會(huì)報(bào)錯(cuò) use-expressions:用于指定intercept-url中的access屬性是否使用表達(dá)式 --> <security:http auto-config="true" use-expressions="true"> <security:headers> <!--設(shè)置在頁(yè)面可以通過(guò)iframe訪問(wèn)受保護(hù)的頁(yè)面,默認(rèn)為不允許訪問(wèn)--> <security:frame-options policy="SAMEORIGIN"></security:frame-options> </security:headers> <!-- intercept-url:定義一個(gè)攔截規(guī)則 pattern:對(duì)哪些url進(jìn)行權(quán)限控制 access:在請(qǐng)求對(duì)應(yīng)的URL時(shí)需要什么權(quán)限,默認(rèn)配置時(shí)它應(yīng)該是一個(gè)以逗號(hào)分隔的角色列表, 請(qǐng)求的用戶只需擁有其中的一個(gè)角色就能成功訪問(wèn)對(duì)應(yīng)的URL --> <!--只需要認(rèn)證通過(guò)就可以訪問(wèn)--> <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/> <!--如果我們要使用自己指定的頁(yè)面作為登錄頁(yè)面,必須配置登錄表單--> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/pages/main.html" authentication-failure-url="/login.html"/> <!--csrf:對(duì)應(yīng)CsrfFilter過(guò)濾器 disabled:是否啟用CsrfFilter過(guò)濾器,如果使用自定義登錄頁(yè)面需要關(guān)閉此項(xiàng),否則登錄操作會(huì)被禁用(403) --> <security:csrf disabled="true"/> <!-- logout:退出登錄 logout-url:退出登錄操作對(duì)應(yīng)的請(qǐng)求路徑 logout-success-url:退出登錄后的跳轉(zhuǎn)頁(yè)面 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/> </security:http> <!--authentication-manager:認(rèn)證管理器,用于處理認(rèn)證操作--> <security:authentication-manager> <!--authentication-provider:認(rèn)證提供者,執(zhí)行具體的認(rèn)證邏輯--> <security:authentication-provider user-service-ref="springSecurityUserService"> <!--引用密碼加密處理bean--> <security:password-encoder ref="passwordEncoder"/> </security:authentication-provider> </security:authentication-manager> <!--配置密碼加密對(duì)象--> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> <!--開(kāi)啟注解方式權(quán)限控制--> <security:global-method-security pre-post-annotations="enabled"/> </beans>
注意:<security:headers>的配置,如果沒(méi)有配置這個(gè)對(duì)象就會(huì)訪問(wèn)不了嵌套的頁(yè)面,哪怕是登錄了也不行
在springmvc.xml配置文件中引入springSecurity.xml
配置文件
<import resource="spring-security.xml"/>
測(cè)試
賬號(hào)為:admin 密碼:admin admin加密后的形式為(存儲(chǔ)到數(shù)據(jù)庫(kù)):$2a$10$LPbhiutR34wKvjv3Qb8zBu7piw5hG3.IlQMAI3e/D1Y0DJ/mMSkYa
3、在控制器上實(shí)現(xiàn)注解鑒權(quán)
注意:是在每一個(gè)控制器上面添加不同的權(quán)限,設(shè)置權(quán)限的只不能亂設(shè)置需要與數(shù)據(jù)庫(kù)進(jìn)行比對(duì)的才可以
// 添加數(shù)據(jù) @PreAuthorize("hasAuthority('CHECKITEM_ADD')") // 查詢數(shù)據(jù) @PreAuthorize("hasAuthority('CHECKITEM_QUERY')") // 刪除數(shù)據(jù) @PreAuthorize("hasAuthority('CHECKITEM_DELETE')") // 修改數(shù)據(jù) @PreAuthorize("hasAuthority('CHECKITEM_EDIT')")
"hasAuthority('CHECKITEM_ADD')"
里面的值需要與數(shù)據(jù)庫(kù)的權(quán)限值一致
模擬沒(méi)有權(quán)限刪除數(shù)據(jù):
1、登錄第二個(gè)賬戶:xiaoming
2、賬戶中沒(méi)有刪除檢查項(xiàng),所以我們就已刪除來(lái)測(cè)試
3、點(diǎn)擊刪除的時(shí)候前端頁(yè)面不會(huì)提示,查看后端控制器代碼,發(fā)現(xiàn)被攔截了,如下報(bào)錯(cuò):
4、切換回有刪除權(quán)限的用戶,刪除查看效果
3.1、完善前端頁(yè)面訪問(wèn)權(quán)限不足提示
在前端代碼中編寫(xiě)一個(gè)方法被多個(gè)請(qǐng)求不成功函數(shù)所調(diào)用
showMessage(r){ if(r == 'Error: Request failed with status code 403'){ //權(quán)限不足 this.$message.error('無(wú)訪問(wèn)權(quán)限'); return; }else{ this.$message.error('未知錯(cuò)誤'); return; } }
在所有的請(qǐng)求方法上添加一個(gè)catch
事件調(diào)用函數(shù)
// 發(fā)送刪除數(shù)據(jù) axios.get("/checkitem/delete.do?id="+row.id).then((res) => { // ... 回調(diào)方法 }).catch ((r) => { this.showMessage(r); });
當(dāng)用戶操作時(shí)如果沒(méi)有權(quán)限那么后端控制器就會(huì)將請(qǐng)求攔截下來(lái),并在后端控制臺(tái)打印攔截提示,同時(shí)前端頁(yè)面回根據(jù)返回的報(bào)錯(cuò)類型做出無(wú)權(quán)限的提示信息,從而提高用戶體驗(yàn)
4、請(qǐng)求獲取當(dāng)前登錄的用戶名信息
請(qǐng)求控制器獲取用戶名信息返回頁(yè)面模型綁定給
username
用于展示
// 發(fā)送ajax請(qǐng)求獲取當(dāng)前登錄的用戶名,展示到頁(yè)面中 axios.get("/user/getUsername.do").then((res) => { if(res.data.flag){ this.username = res.data.data; } })
請(qǐng)求后端控制器編寫(xiě)
@RestController @RequestMapping("/user") public class UserController { @RequestMapping("/getUsername") public Result getUsername(){ // 當(dāng)springsecurity完成認(rèn)證后,會(huì)將當(dāng)前用戶信息保存到框架提供的上下文對(duì)象中 User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (user != null) { System.out.println(user.getUsername()); return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,user.getUsername()); } return new Result(false, MessageConstant.GET_USERNAME_FAIL); } }
5、用戶退出
前端請(qǐng)求
<el-dropdown-item divided> <span style="display:block;"><a href="/logout.do" rel="external nofollow" >退出</a></span> </el-dropdown-item>
后端配置文件中進(jìn)行退出跳轉(zhuǎn)設(shè)置
<!-- logout:退出登錄 logout-url:退出登錄操作對(duì)應(yīng)的請(qǐng)求路徑 logout-success-url:退出登錄后的跳轉(zhuǎn)頁(yè)面 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>
到此這篇關(guān)于詳解如何在項(xiàng)目中應(yīng)用SpringSecurity權(quán)限控制的文章就介紹到這了,更多相關(guān)SpringSecurity權(quán)限控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合Security權(quán)限控制登錄首頁(yè)
- SpringBoot?整合Security權(quán)限控制的初步配置
- Spring?Security權(quán)限管理實(shí)現(xiàn)接口動(dòng)態(tài)權(quán)限控制
- Spring?Security實(shí)現(xiàn)統(tǒng)一登錄與權(quán)限控制的示例代碼
- 基于Spring Security前后端分離的權(quán)限控制系統(tǒng)問(wèn)題
- 詳解Spring Security 中的四種權(quán)限控制方式
- SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析
- Spring?Security權(quán)限控制的實(shí)現(xiàn)接口
相關(guān)文章
劍指Offer之Java算法習(xí)題精講鏈表與字符串及數(shù)組
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03java Socket無(wú)法完全接收返回內(nèi)容的解決方案
這篇文章主要介紹了java Socket無(wú)法完全接收返回內(nèi)容的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10ShardingSphere數(shù)據(jù)庫(kù)讀寫(xiě)分離算法及測(cè)試示例詳解
這篇文章主要為大家介紹了ShardingSphere數(shù)據(jù)庫(kù)讀寫(xiě)分離算法及測(cè)試示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03idea 右鍵項(xiàng)目沒(méi)有run 運(yùn)行選項(xiàng)
這篇文章主要介紹了idea 右鍵項(xiàng)目沒(méi)有run 運(yùn)行選項(xiàng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06注入jar包里的對(duì)象,用@autowired的實(shí)例
這篇文章主要介紹了注入jar包里的對(duì)象,用@autowired的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09SpringMVC數(shù)據(jù)頁(yè)響應(yīng)ModelAndView實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)
本文主要介紹了SpringMVC數(shù)據(jù)頁(yè)響應(yīng)ModelAndView實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07談?wù)凧ava中對(duì)象,類和this,super,static關(guān)鍵字的使用
對(duì)象:對(duì)象是類的一個(gè)實(shí)例,有狀態(tài)和行為。類:類是一個(gè)模板,它描述一類對(duì)象的行為和狀態(tài)。本文就來(lái)和大家聊聊Java中對(duì)象,類和關(guān)鍵字的使用,需要的可以參考一下2022-08-08淺談Java當(dāng)作數(shù)組的幾個(gè)應(yīng)用場(chǎng)景
數(shù)組可以存放多個(gè)同一類型的數(shù)據(jù),可以存儲(chǔ)基本數(shù)據(jù)類型,引用數(shù)據(jù)類型(對(duì)象),下面這篇文章主要給大家介紹了關(guān)于Java當(dāng)作數(shù)組的幾個(gè)應(yīng)用場(chǎng)景,需要的朋友可以參考下2022-11-11