在項目中使用Spring Security進行權(quán)限控制

1:導(dǎo)入Spring Security環(huán)境
(1)pom.xml中添加依賴
(2)web.xml添加代理過濾器
2:實現(xiàn)認證和授權(quán)
(1)認證:SpringSecurityUserService.java
(2)創(chuàng)建Service類挂谍、Dao接口類瞎饲、Mapper映射文件
(3)springmvc.xml(dubbo注解掃描范圍擴大)
(4)spring-security.xml
(5)springmvc.xml(導(dǎo)入spring-security.xml)
(6)TravelItemController類(@PreAuthorize("hasAuthority('CHECKITEM_ADD')"):完成權(quán)限)
(7)travelitem.html(如果沒有權(quán)限嗅战,可以提示錯誤信息)
(8)導(dǎo)入login.html測試登錄
3:顯示用戶名
4:用戶退出

1.1導(dǎo)入Spring Security環(huán)境

【路徑】
1:pom.xml導(dǎo)入坐標
2:web.xml添加代理過濾器

1.1.1.第一步:pom.xml導(dǎo)入坐標

在父工程的pom.xml中導(dǎo)入Spring Security的maven坐標

            <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.2.第二步:web.xml添加代理過濾器

在meinian_web工程的web,xml文件中配置用于整合Spring Security框架的過濾器DelegatingFilterProxy

    <filter>
        <!--
          DelegatingFilterProxy用于整合第三方框架(代理過濾器,非真正的過濾器驮捍,真正的過濾器需要在spring的配置文件)
          整合Spring Security時過濾器的名稱必須為springSecurityFilterChain东且,
          否則會拋出NoSuchBeanDefinitionException異常
        -->
        <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>

1.1.3.第三步:sql語句

#1 使用登錄名查詢用戶信息
SELECT * FROM t_user WHERE username='admin'
#2 傳遞用戶id查詢角色合集
SELECT r.* FROM t_role r, t_user_role ur WHERE ur.role_id = r.id AND ur.user_id=1
# 傳遞角色id查詢權(quán)限集合
SELECT p.* FROM t_permission p, t_role_permisson rp WHERE p.id = rp.permission_id AND rp.role_id = 1

實現(xiàn)認證和授權(quán)

1.2.1.第一步:SpringSecurityUserService.java

在meinian_web工程中按照Spring Security框架要求提供SpringSecurityUserService,并且實現(xiàn)UserDetailsSercice接口

package com.atguigu.security;

import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.pojo.Permission;
import com.atguigu.pojo.Role;
import com.atguigu.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.HashSet;
import java.util.Set;

@Component 
public class SpringSecurityUserService implements UserDetailsService {

    @Reference
    UserService userService; // 遠程調(diào)用

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 1.查詢用戶信息鲁冯,以及用戶對應(yīng)的角色色查,以及角色對應(yīng)的權(quán)限
        com.atguigu.pojo.User user = userService.findUserByUserName(username);
        if (user==null){
            // 不存在這個用戶
            return null;// 返回null給框架,框架會拋異常處理跨扮,跳轉(zhuǎn)到登錄頁面
        }
        // 2.構(gòu)建權(quán)限集合
        Set<GrantedAuthority> authorities = new HashSet<>();

        Set<Role> roles = user.getRoles(); //集合數(shù)據(jù) 由RoleDao幫忙方法來查詢得到的
        for (Role role : roles) {
            Set<Permission> permissions = role.getPermissions(); // 集合數(shù)據(jù) 有 PermissionDao幫忙方法查詢得到的
            for (Permission permission : permissions) {
                authorities.add(new SimpleGrantedAuthority(permission.getKeyword()));
            }
        }
        org.springframework.security.core.userdetails.User securityUser = 
                new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
        
        return securityUser; // 框架提供的User實現(xiàn)了UserDetails接口
    }
}

1.2.2.第二步:Service示惊、Dao接口、Mapper映射文件

創(chuàng)建UserService服務(wù)接口钧汹、服務(wù)實現(xiàn)類录择、Dao接口碗降、Mapper映射文件
【路徑】
1:UserService.java 接口
2:UserServiceImpl.java 類
3:UserDao.java(使用用戶id查詢用戶)
4:RoleDao.java (使用用戶id查詢角色集合)
5:PermissionDao.java(使用角色id查詢權(quán)限集合)
6:UserDao.xml(使用用戶id查詢用戶)
7:RoleDao.xml(使用用戶id查詢角色集合)
8:PermissionDao.xml (使用角色id查詢權(quán)限集合)

使用debug跟蹤調(diào)試塘秦,查看user


ad539466-82bf-4461-84ba-01f1a0e6b2f1.jpg

1.2.3.第三步:springmvc.xml

修改meinian_web工程中的springmvc.xml文件,修改dubbo批量掃描的包路徑
之前的掃描包

        <!--批量掃描 -->
    <dubbo:annotation package="com.atguigu.controller" />

現(xiàn)在的掃描包

    <!--批量掃描尊剔, 范圍要變大,不然掃描不到SpringSecurityUserService包-->
    <dubbo:annotation package="com.atguigu" />

注意:

此處原來掃描的包為com.atguigu.controller须误,現(xiàn)在改為com.atguigu包的目的是需要將我們上面定義的SpringSecurityUserService也掃描到,因為在SpringSecurityUserService的loadUserByUsername方法中需要通過dubbo遠程調(diào)用名稱為UserService的服務(wù)

1.2.4.第四步:spring-security.xml

【路徑】
1:定義哪些鏈接可以放行
2:定義哪些鏈接不可以方向奶甘,即需要有角色祭椰、權(quán)限才可以放行
3:認證管理臭家,定義登錄賬號和密碼钉赁,并授權(quán)訪問的角色臣淤、權(quán)限
4:設(shè)置在頁面可以通過iframe訪問受保護的頁面,默認為不允許默認訪問邑蒋,需要添加security:frame-optionspolicy=”SAMEORIGIN“
【講解】
在meinian_web工程中提供spring-security.xml配置文件

<?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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd
                  http://www.springframework.org/schema/mvc
                  http://www.springframework.org/schema/mvc/spring-mvc.xsd
                  http://code.alibabatech.com/schema/dubbo
                  http://code.alibabatech.com/schema/dubbo/dubbo.xsd
                  http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context.xsd
                          http://www.springframework.org/schema/security
                          http://www.springframework.org/schema/security/spring-security.xsd">

    <!--靜態(tài)資源放行 對css不做權(quán)限判斷-->
    <security:http security="none" pattern="/css/**"/>
    <security:http security="none" pattern="/img/**"/>
    <security:http security="none" pattern="/js/**"/>
<!--    <security:http security="none" pattern="/pages/**"/>-->
    <security:http security="none" pattern="/template/**"/>
    <security:http security="none" pattern="/plugins/**"/>
    <security:http security="none" pattern="/login.html"/>

    <!-- 對控制器中的方法提供注解的權(quán)限驗證-->
    <security:global-method-security pre-post-annotations="enabled"/>

    <security:http auto-config="true" use-expressions="true">
        <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/>

        <security:form-login login-page="/login.html"
                             login-processing-url="/login.do"
                             username-parameter="username"
                             password-parameter="password"
                             default-target-url="/pages/main.html"
                             always-use-default-target="true"
                             authentication-failure-forward-url="/login.html"
        />
        <!--禁用csrf的獲取使用-->
        <security:csrf disabled="true"/>

        <security:logout logout-success-url="/login.html" logout-url="/logout.do" invalidate-session="true"/>

        <security:headers>
            <!--設(shè)置在頁面可以通過iframe訪問受保護的頁面,默認為不允許訪問-->
            <security:frame-options policy="SAMEORIGIN"/>
        </security:headers>

        <security:access-denied-handler ref="customAccessDeniedHandler"/>
    </security:http>

    <!--認證authentication(登錄)-->
    <security:authentication-manager>
        <!--使用userServiceImpl進行登錄-->
        <security:authentication-provider user-service-ref="userServiceImpl">
            <security:password-encoder ref="bcry"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="bcry" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

</beans>

在spring-security.xml中添加
放置到 <security:http auto-config="true" use-expressions="true"> 里面

        <security:headers>
            <!--設(shè)置在頁面可以通過iframe訪問受保護的頁面卿堂,默認為不允許訪問-->
            <security:frame-options policy="SAMEORIGIN"/>
        </security:headers>

因為我們在main.html中定義: 如果不配置springSecurity 會認為iframe訪問的html頁面時受保護的頁面懒棉,不允許訪問。

1.2.5.第五步: springmvc.xml

在springmvc,xml文件中引入spring-security.xml文件

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

1.2.6.第六步: TravelItemController 類 授權(quán)

在Controller的方法上加入權(quán)限 控制注解策严,此處以TravelItemController為例

    @RequestMapping("/update")
    @PreAuthorize("hasAuthority('TRAVELITEM_EDIT')") // 權(quán)限校驗
    public Result update(@RequestBody TravelItem travelItem){

        try {
            travelItemService.update(travelItem);
            return new Result(true, MessageConstant.EDIT_TRAVELITEM_SUCCESS);

        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.EDIT_TRAVELITEM_FAIL);

        }
    }

1.2.7第七步: CustomAccessDeniedHandler類

添加頁面妻导,沒有權(quán)限時提示信息設(shè)置
1.在<security:http>標簽中增加<security:access-denied-handler>

        <!--    自定義異常處理類    -->
        <security:access-denied-handler ref="customAccessDeniedHandler"/>

2.增加自定義處理類


    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
                       AccessDeniedException accessDeniedException) throws IOException, ServletException {
        if (isAjaxRequest(request)) {// AJAX請求,使用response發(fā)送403
            Result result = new Result(false, "無權(quán)訪問","403");
            String json = JSON.toJSONString(result);
            response.getWriter().print(json);// 不要使用prinln方法怀各,含有回車換行符
        } else{// 同步請求處理
            request.getRequestDispatcher("/pages/error/403.html").forward(request,response);
        }
    }


    /**
     * 判斷是否為ajax請求
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        if (request.getHeader("accept").indexOf("application/json") > -1
                || (request.getHeader("X-Requested-With") != null
                && request.getHeader("X-Requested-With").equalsIgnoreCase("XMLHttpRequest"))) {
            return true;
        }
        return false;
    }

3.增加/pages/error/403.html頁面

1.2.8.第八步: 導(dǎo)入login.html頁面

1.3.顯示用戶名

【路徑】
1:引入js
2:定義username屬性
3:使用鉤子函數(shù)术浪,調(diào)用ajax,查詢登錄用戶(從SpringSecurity中獲取)硕蛹,復(fù)制username屬性
4:修改頁面硕并,使用{username}顯示用戶信息
【講解】
前面我們已經(jīng)完成了認證和授權(quán)操作,如果用戶認證成功后需要在頁面顯示當前用戶的用戶名鲤孵,Spring Security在認證成功后會將用戶信息保存到框架提供的上下文對象中普监,所以此處我們就可以調(diào)用Spring Security框架提供的api獲取當前用戶的username 并展示到頁面上
實現(xiàn)步驟:
第一步:在mian.html頁面中修改,定義username模型數(shù)據(jù)基于VUE的數(shù)據(jù)展示用戶名凯正,發(fā)送Ajax請求獲取username
(1):引入js

<scipt src ="../js/axios-0.18.0.js">

(2):定義username屬性
(3):使用鉤子函數(shù),調(diào)用ajax
(4):修改頁面
顯示當前登錄人

1.4用戶退出

【路徑】
1:在main,html中提供的退出菜單上加入超鏈接
2:在Spring-security.xml文件中配置
【講解】
第一步:在main.html中提供的退出菜單上加入超鏈接

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

第二步:在Spring-security.xml文件中配置

        <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桑滩,一起剝皮案震驚了整個濱河市允睹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胁澳,老刑警劉巖米者,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胰丁,居然都是意外死亡喂分,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門酸员,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幔嗦,你說我怎么就攤上這事℃业玻” “怎么了汇恤?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長基括。 經(jīng)常有香客問我财岔,道長,這世上最難降的妖魔是什么匠璧? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任夷恍,我火速辦了婚禮,結(jié)果婚禮上酿雪,老公的妹妹穿的比我還像新娘。我一直安慰自己拓挥,他們只是感情好袋励,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布当叭。 她就那樣靜靜地躺著,像睡著了一般磺芭。 火紅的嫁衣襯著肌膚如雪醉箕。 梳的紋絲不亂的頭發(fā)上徙垫,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天放棒,我揣著相機與錄音,去河邊找鬼间螟。 笑死,一個胖子當著我的面吹牛荣瑟,可吹牛的內(nèi)容都是我干的摩泪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嚷掠,長吁一口氣:“原來是場噩夢啊……” “哼鳄梅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起戴尸,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤孙蒙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挎峦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡透典,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年顿苇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凑队。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡幔翰,死狀恐怖西壮,靈堂內(nèi)的尸體忽然破棺而出叫惊,到底是詐尸還是另有隱情,我是刑警寧澤赋访,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布蚓耽,位于F島的核電站,受9級特大地震影響步悠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜答姥,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一谚咬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧择卦,春花似錦、人聲如沸祈噪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽月褥。三九已至,卻和暖如春吓坚,著一層夾襖步出監(jiān)牢的瞬間灯荧,已是汗流浹背盐杂。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工哆窿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厉斟,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓码荔,卻偏偏與公主長得像感挥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子触幼,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容