首頁 > 軟體

詳解如何在專案中應用SpringSecurity許可權控制

2022-06-26 18:01:46

要進行認證和授權需要前面課程中提到的許可權模型涉及的7張表支撐,因為使用者資訊、許可權資訊、選單資訊、角色資訊、關聯資訊等都儲存在這7張表中,也就是這些表中的資料是我們進行認證和授權的依據。所以在真正進行認證和授權之前需要對這些資料進行管理,即我們需要開發如下一些功能:

1、許可權資料管理(增刪改查)

2、選單資料管理(增刪改查)

3、角色資料管理(增刪改查、角色關聯許可權、角色關聯選單)

4、使用者資料管理(增刪改查、使用者關聯角色)

資料庫資料實現匯入,簡化上面的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', '新增檢查項', 'CHECKITEM_ADD', null);
INSERT INTO `t_permission` VALUES ('2', '刪除檢查項', 'CHECKITEM_DELETE', null);
INSERT INTO `t_permission` VALUES ('3', '編輯檢查項', 'CHECKITEM_EDIT', null);
INSERT INTO `t_permission` VALUES ('4', '查詢檢查項', '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', '預約設定', 'ORDERSETTING', null);
INSERT INTO `t_permission` VALUES ('14', '檢視統計報表', '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', '系統管理員', '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環境準備

pom.xml中匯入Spring Security的maven座標,目前版本使用的是5.0.5.RELEASE,版本如果過高可能就會導致不同的報錯

<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框架的過濾器DelegatingFilterProxy

<!--委派過濾器,用於整合其他框架-->
<filter>
  <!--整合spring security時,此過濾器的名稱固定springSecurityFilterChain-->
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<!--注意區分放置的位置,有嚴格的先後順序-->
<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

2、實現認證和授權

在health_backend工程中按照Spring Security框架要求提供SpringSecurityUserService,並且實現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;

/**
 * 專案名稱:health_parent
 * 描述:SpringSecurity實現認證和授權
 *
 * @author zhong
 * @date 2022-06-24 12:09
 */
@Component
public class SpringSecurityUserService implements UserDetailsService {

    /**
     * 使用dubbo網路遠端呼叫服務提供方查詢使用者資料
     */
    @Reference
    private UserService userService;

    /**
     * 根據使用者名稱查詢資料庫獲取使用者資訊
     * @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<>();
        // 動態為當前使用者授權
        Set<Role> roles = user.getRoles();
        // 遍歷角色集合,為使用者授予角色
        for (Role role : roles) {
            // 為使用者授予角色
            list.add(new SimpleGrantedAuthority(role.getKeyword()));
            // 獲取許可權
            Set<Permission> permissions = role.getPermissions();
            // 遍歷許可權,為角色授權
            for (Permission permission : permissions) {
                list.add(new SimpleGrantedAuthority(permission.getKeyword()));
            }
        }

        /*
         * 將密碼交由框架比對
         * 引數一:賬號
         * 引數二:查詢資料庫的密碼,已加密的
         * 引數三:使用者角色所具有的許可權
         */
        org.springframework.security.core.userdetails.User UserSecurity = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list);
        return UserSecurity;
    }
}

建立遠端呼叫的UserService介面

public interface UserService {
    /**
     * 根據登入名查詢使用者資料
     * @param username
     * @return
     */
    User findByUsername(String username);
}

建立介面實現類

需要注入資料存取層來完成資料的查詢,使用者、角色、許可權各自建立一個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;

/**
 * 專案名稱:health_parent
 * 描述:使用者服務實現類
 *
 * @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;

    /**
     * 根據使用者名稱稱查詢使用者角色資訊和關聯的角色資訊,同時需要查詢角色關聯的許可權資訊
     * @param username
     * @return
     */
    @Override
    public User findByUsername(String username) {
        // 1、查詢使用者基本資訊,不包含使用者角色資訊
        User user = userDao.findByUsername(username);
        if(user == null){
            return null;
        }
        // 2、根據使用者查詢的使用者id查詢角色資訊
        Integer userId = user.getId();
        Set<Role> roles = roleDao.findByUserId(userId);
        // 3、根據角色來查詢許可權
        for (Role role : roles) {
            Integer roleId = role.getId();
            Set<Permission> permissions = permissionDao.findByRoleId(roleId);
            // 讓角色關聯許可權
            role.setPermissions(permissions);
        }
        // 讓用還關聯角色
        user.setRoles(roles);
        return user;
    }
}

建立【使用者、角色、許可權】資料存取層介面

注意:這三個介面都不是在同一個類中的,而是各自獨立的介面類,不要寫在一起

public interface UserDao {
    User findByUsername(String username);
}

public interface RoleDao {
    Set<Role> findByUserId(Integer userId);
}

public interface PermissionDao {
    Set<Permission> findByRoleId(Integer roleId);
}

查詢使用者的Mapper對映檔案查詢資料

對映檔案建立在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">
    <!--根據使用者名稱稱查詢使用者資訊-->
    <select id="findByUsername" parameterType="string" resultType="com.itheima.pojo.User">
        select *
        from t_user
        where username = #{username}
    </select>
</mapper>

根據使用者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">
    <!--根據使用者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>

根據角色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.PermissionDao">
    <!--根據角色id查詢許可權-->
    <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的批次掃描

原因:預設設定的dubbo掃描的是Controller包下的,所以我們建立了一個新的包server用於存放許可權實現類,而實現類剛好也是使用dubbo來遠端呼叫介面查詢資料庫的,需要使用到dubbo就需要被掃描到

<!--批次掃描-->
<dubbo:annotation package="com.zcl" />

建立springSecurity.xml組態檔

與上一篇的入門案例不同的是,SpringSecurityUserService認證提供者不需要在組態檔裡面建立bean交給spring容器了,因為在類的上面已經使用@Component建立,在spring容器中已經有了,通過小寫字母即可參照

如果參照認證類報紅就不需要管,影響不到程式,只是IDEA的檢測問題

<?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">

    <!--設定哪些資源匿名可以存取的資源(不登入頁可以存取)-->
    <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:用於定義相關許可權控制
        auto-config:是否自動設定
                        設定為true時框架會提供預設的一些設定,例如提供預設的登入頁面、登出處理等
                        設定為false時需要顯示提供登入表單設定,否則會報錯
        use-expressions:用於指定intercept-url中的access屬性是否使用表示式
    -->
    <security:http auto-config="true" use-expressions="true">
        <security:headers>
            <!--設定在頁面可以通過iframe存取受保護的頁面,預設為不允許存取-->
            <security:frame-options policy="SAMEORIGIN"></security:frame-options>
        </security:headers>
        <!--
            intercept-url:定義一個攔截規則
            pattern:對哪些url進行許可權控制
            access:在請求對應的URL時需要什麼許可權,預設設定時它應該是一個以逗號分隔的角色列表,
				  請求的使用者只需擁有其中的一個角色就能成功存取對應的URL
        -->
        <!--只需要認證通過就可以存取-->
        <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/>

        <!--如果我們要使用自己指定的頁面作為登入頁面,必須設定登入表單-->
        <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:對應CsrfFilter過濾器
            disabled:是否啟用CsrfFilter過濾器,如果使用自定義登入頁面需要關閉此項,否則登入操作會被禁用(403) -->
        <security:csrf disabled="true"/>

        <!--
          logout:退出登入
          logout-url:退出登入操作對應的請求路徑
          logout-success-url:退出登入後的跳轉頁面
        -->
        <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>
    </security:http>
    <!--authentication-manager:認證管理器,用於處理認證操作-->
    <security:authentication-manager>
        <!--authentication-provider:認證提供者,執行具體的認證邏輯-->
        <security:authentication-provider user-service-ref="springSecurityUserService">
            <!--參照密碼加密處理bean-->
            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <!--設定密碼加密物件-->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

    <!--開啟註解方式許可權控制-->
    <security:global-method-security pre-post-annotations="enabled"/>
</beans>

注意:<security:headers>的設定,如果沒有設定這個物件就會存取不了巢狀的頁面,哪怕是登入了也不行

在springmvc.xml組態檔中引入springSecurity.xml組態檔

<import resource="spring-security.xml"/>

測試

賬號為:admin
密碼:admin
admin加密後的形式為(儲存到資料庫):$2a$10$LPbhiutR34wKvjv3Qb8zBu7piw5hG3.IlQMAI3e/D1Y0DJ/mMSkYa

3、在控制器上實現註解鑑權

注意:是在每一個控制器上面新增不同的許可權,設定許可權的只不能亂設定需要與資料庫進行比對的才可以

// 新增資料
@PreAuthorize("hasAuthority('CHECKITEM_ADD')")

// 查詢資料
@PreAuthorize("hasAuthority('CHECKITEM_QUERY')")

// 刪除資料
@PreAuthorize("hasAuthority('CHECKITEM_DELETE')")

// 修改資料
@PreAuthorize("hasAuthority('CHECKITEM_EDIT')")

"hasAuthority('CHECKITEM_ADD')"裡面的值需要與資料庫的許可權值一致

模擬沒有許可權刪除資料:

1、登入第二個賬戶:xiaoming

2、賬戶中沒有刪除檢查項,所以我們就已刪除來測試

3、點選刪除的時候前端頁面不會提示,檢視後端控制器程式碼,發現被攔截了,如下報錯:

4、切換回有刪除許可權的使用者,刪除檢視效果

3.1、完善前端頁面存取許可權不足提示

在前端程式碼中編寫一個方法被多個請求不成功函數所呼叫

showMessage(r){
    if(r == 'Error: Request failed with status code 403'){
        //許可權不足
        this.$message.error('無存取許可權');
        return;
    }else{
        this.$message.error('未知錯誤');
        return;
    }
}

在所有的請求方法上新增一個catch事件呼叫函數

// 傳送刪除資料
axios.get("/checkitem/delete.do?id="+row.id).then((res) => {
    // ... 回撥方法
}).catch ((r) => {
    this.showMessage(r);
});

當用戶操作時如果沒有許可權那麼後端控制器就會將請求攔截下來,並在後端控制檯列印攔截提示,同時前端頁面回根據返回的報錯型別做出無許可權的提示資訊,從而提高使用者體驗

4、請求獲取當前登入的使用者名稱資訊

請求控制器獲取使用者名稱資訊返回頁面模型繫結給username用於展示

// 傳送ajax請求獲取當前登入的使用者名稱,展示到頁面中
axios.get("/user/getUsername.do").then((res) => {
    if(res.data.flag){
        this.username = res.data.data;
    }
})

請求後端控制器編寫

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getUsername")
    public Result getUsername(){
        // 當springsecurity完成認證後,會將當前使用者資訊儲存到框架提供的上下文物件中
        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、使用者退出

前端請求

<el-dropdown-item divided>
  <span style="display:block;"><a href="/logout.do" rel="external nofollow" >退出</a></span>
</el-dropdown-item>

後端組態檔中進行退出跳轉設定

<!--
  logout:退出登入
  logout-url:退出登入操作對應的請求路徑
  logout-success-url:退出登入後的跳轉頁面
-->
<security:logout logout-url="/logout.do" 
                 logout-success-url="/login.html" invalidate-session="true"/>

到此這篇關於詳解如何在專案中應用SpringSecurity許可權控制的文章就介紹到這了,更多相關SpringSecurity許可權控制內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com