Spring Security小教程 Vol 1. 快速為Spring Boot添加鑒權(quán)授權(quán)功能

噗噗虎和阿基拉的廢柴大叔小課堂

本文閱讀約需要10分鐘
本期的配套視頻講解請?jiān)L問https://www.bilibili.com/video/av45427128/

前言

本系列開坑編寫的動機(jī)是為了在中文圈為Spring Security的推廣、使用舔磚加瓦。因?yàn)镾pring Security幾乎對所有Spring應(yīng)用都有存在的意義张肾,所以我們第一期就把Spring Security作為我們教程的第一個話題。同期我們也制作了每期10分鐘的視頻講解,希望可以彌補(bǔ)僅僅使用文字和圖片描述一個技術(shù)知識點(diǎn)上給讀者帶來的困擾炸渡。

最后,在本系列編寫期間丽已,我們使用的SpringBoot版本為1.5蚌堵;Security版本為4。如因版本差異導(dǎo)致的無法正常運(yùn)行和獲取期望結(jié)果的情況發(fā)生沛婴,可以通過評論私信給予我們反饋吼畏。謝謝。

第一期 快速為Spring Boot應(yīng)用添加Spring Security

本期的任務(wù)清單

  1. 快速初始化一個Spring Boot項(xiàng)目
  2. 如何添加基于內(nèi)存的用戶鑒權(quán)功能
  3. 如何添加基于角色的訪問控制邏輯

1嘁灯、快速初始化一個Spring Boot項(xiàng)目

我們推薦初學(xué)者如果對Maven的pom.xml編寫和spring各種starter依賴不熟悉的情況下泻蚊,使用Spring官方提供的項(xiàng)目初始化工具進(jìn)行生成。https://start.spring.io/
我們的目的是初始化一個基于SpringBoot的Web應(yīng)用丑婿,并且包含了Security的相關(guān)組件性雄。所以在工具的Web界面上依賴組件部分,需要依次鍵入并選擇Web羹奉、Security和Thymeleaf三個組件依賴秒旋。
點(diǎn)擊生成后,瀏覽器便會自動下載一個項(xiàng)目工程壓縮包诀拭。

https://start.spring.io/

解壓縮代碼之后迁筛,通過IDEA導(dǎo)入后便會得到一個已經(jīng)包含了Security的基礎(chǔ)SpringBoot應(yīng)用。
運(yùn)行DemoApplication.java炫加,在控制臺看到應(yīng)用啟動完畢后瑰煎,通過瀏覽器訪問本機(jī)的127.0.0.1:8080端口,如看到提示輸入用戶名和密碼的登錄對話框俗孝,那么就代表了Security已經(jīng)成功的加載到了應(yīng)用中酒甸。

默認(rèn)登錄對話框

2、添加基于內(nèi)存的用戶鑒權(quán)功能

鑒權(quán)和訪問控制的區(qū)分

鑒權(quán)和授權(quán)

首先赋铝,我們要對Authentication和Authorization兩個詞做一個區(qū)別插勤。在中文語義上我們會把Authentication稱為鑒權(quán),用戶認(rèn)證,通常是一個對根據(jù)某些信息农尖、比如用戶名析恋、密碼、令牌等來辨別用戶的過程盛卡。而Authorization在中文語義上可以理解為授權(quán)助隧、訪問控制。為了將來好區(qū)別我們將來會統(tǒng)一把Authorization稱為訪問控制(Access Control)滑沧,因?yàn)锳uthorization是根據(jù)用戶的角色并村、權(quán)限等信息來判斷目標(biāo)行為、資源是不是可以被對應(yīng)的用戶使用滓技、消費(fèi)哩牍。
簡單的說,鑒權(quán)就是用戶登錄令漂、授權(quán)就是權(quán)限控制膝昆。

而我們的第二個任務(wù)就是配置Security框架使其可以正確的獲取用戶信息用于登錄檢查。
我們選擇通過JavaConfig的方式類編寫這個配置叠必,類名我們?nèi)∶蠾ebSecurityConfig荚孵,并鍵入下面的代碼。

@EnableWebSecurity //配置注解
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {
    //注入新的UserDetailsServiceBean
    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("password").roles("USER").build());
        return manager;
    }
}

我們在代碼中主要完成的工作就注入了一個\color{red}{UserDetailsService}的組件挠唆。那么什么是\color{red}{UserDetailsService}呢处窥?

UserDetailsService 和 UserDetails

UserDetails是我們接觸的第一個重要概念嘱吗。在Spring Security的觀點(diǎn)中玄组,UserDetails就好比我們自行設(shè)計(jì)系統(tǒng)的用戶、賬戶的概念谒麦。他包含了用戶名俄讹、密碼和其對應(yīng)的授予權(quán)限。

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

UserDetailsSevice就是當(dāng)前系統(tǒng)中如何獲取庫存用戶信息的服務(wù)绕德。

public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}}

在這里就可以簡單的認(rèn)為患膛,在我們輸入用戶名和密碼之后,框架便會通過UserDetailsService 的實(shí)現(xiàn)類去尋找驗(yàn)證用戶前端輸入的用戶名和密碼是否正確耻蛇,如果正確則返回UserDetails完成登錄操作踪蹬。Security模式提供了許多種方式的用戶信息管理服務(wù)實(shí)現(xiàn),比如基于數(shù)據(jù)庫臣咖、基于LDAP的跃捣。我們當(dāng)前使用的是最簡單基于內(nèi)存的用戶管理實(shí)現(xiàn)InMemoryUserDetailsManager。

InMemoryUserDetailsManager是Security提供的UserDetailsService的實(shí)現(xiàn)類

我們通過新建InMemoryUserDetailsManager夺蛇,然后通過createUser方法向其添加了一條用戶記錄疚漆。最終將其注入Spring框架,使其為我們的應(yīng)用在登錄時候可以正確的查找到我們期望的用戶記錄。

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("password").roles("USER").build());
        return manager;
    }

重啟應(yīng)用后娶聘,重新訪問http://127.0.0.1:8080/的測試應(yīng)用闻镶,在輸入用戶名和密碼后,則會提示目標(biāo)訪問的頁面不存在的404錯誤丸升。這起碼證明登錄邏輯已經(jīng)完成了铆农,稍后簡單編寫一個簡單的控制器和頁面模板就可以完成第二個任務(wù)。
控制器代碼MainController

@Controller
public class MainController {
    @RequestMapping("/")
    public String root() {
        return "index";
    }

頁面模板代碼 index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <title>Hello Spring</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
    <h1>Hello Spring</h1>
</body>
</html>

在登陸后便可以看到我們期望的hello頁面狡耻。


index.html的訪問頁面

3顿涣、 如何添加基于角色的訪問控制邏輯

剛剛一個任務(wù)我們完成了Spring Security兩個主要關(guān)注點(diǎn)之一的鑒權(quán)功能,現(xiàn)在我們就開始實(shí)現(xiàn)一個最簡單的訪問控制邏輯酝豪。
首先涛碑,我們先對當(dāng)前任務(wù)的目標(biāo)做一個簡單的設(shè)計(jì):
我們將在MainController編寫兩個路徑頁面,分別是不需要訪問控制的 ""路徑和需要登錄控制的"\user"路徑孵淘。


基于url的訪問控制設(shè)計(jì)圖

編寫控制器

首先我們根據(jù)設(shè)計(jì)將MainContoller的代碼補(bǔ)全蒲障,添加新的url和對應(yīng)的視圖模板。user.html對先直接復(fù)制index.html瘫证,只是把內(nèi)容改成Welcome User就可以了揉阎。
MainController .java

@Controller
public class MainController {
    @RequestMapping("/")
    public String root() {
        return "index";
    }
    @RequestMapping("/user")
    public String userIndex() {
        return "user";
    }
}

user.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <title>Welcome User</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
    <h1>Welcome User</h1>
</body>
</html>

編寫訪問控制配置

我們的配置類WebSecurityConfig是繼承框架提供的\color{red}{WebSecurityConfigurerAdapter},其中有過一個重要的配置方案我們關(guān)注下框架提供的默認(rèn)值實(shí)現(xiàn):


    protected void configure(HttpSecurity http) throws Exception {
        logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin().and()
            .httpBasic();
    }

這一段代碼主要搞事我們一個HttpSecurity的配置主要有三點(diǎn):

  1. authorizeRequests()下管理路徑訪問控制背捌;
  2. formLogin()管理登錄表單配置毙籽;
  3. httpBasic()是否基于Http的驗(yàn)證配置。
    后兩點(diǎn)不是我們的重點(diǎn)毡庆,我們的目標(biāo)是配置路徑的訪問控制坑赡,所以我們需要在我們自己的配置類覆寫這個方法:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                // inde.html對應(yīng)的url允許所任人訪問
                .antMatchers("/").permitAll()
                // user.html對應(yīng)的url,則需要用戶有USER的角色才可以訪問
                .antMatchers("/user").hasRole("USER")
                .and()
                .formLogin();
    }

我們使用了hasRole()基于角色的驗(yàn)證條件么抗,讓我再回顧下毅否,之前我們在用戶鑒權(quán)部分,添加的用戶記錄的代碼是怎么樣的?我們添加的user用戶其也包含了一個USER的角色蝇刀,而在訪問控制的時候便會檢查這一角色授權(quán)信息是否匹配螟加。

manager.createUser(User.withUsername("user").password("password").roles("USER").build());

重啟應(yīng)用,首先輸入/路徑吞琐,應(yīng)用沒有提示我們?nèi)魏蔚卿泴υ捒蚶μ剑覀兙涂吹搅薍ello Spring的標(biāo)題。


\路徑

接著我們再鍵入\user路徑站粟,因?yàn)樵L問控制檢查到我們沒有完成登錄操作黍图,則將我們重定向到login頁面完成登錄做操

最后,當(dāng)我們完成用戶名和輸入之后卒蘸,因?yàn)橛脩艚巧c期望配置的一致雌隅,我們得以訪問目標(biāo)/user頁面翻默。


\user頁面

這樣我們也完成最簡單的訪問控制配置的任務(wù)。

結(jié)尾

我們在本期中對SpringSecurity最重要的兩個功能:用戶鑒權(quán)和訪問控制做了最簡單的實(shí)現(xiàn)和配置恰起。
在下一期修械,我們將對用戶鑒權(quán)部分的具體流程展開講解。讓我們下期再見检盼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肯污,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吨枉,更是在濱河造成了極大的恐慌蹦渣,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件貌亭,死亡現(xiàn)場離奇詭異柬唯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)圃庭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門锄奢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剧腻,你說我怎么就攤上這事拘央。” “怎么了书在?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵灰伟,是天一觀的道長。 經(jīng)常有香客問我儒旬,道長栏账,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任义矛,我火速辦了婚禮发笔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凉翻。我一直安慰自己,他們只是感情好捻激,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布制轰。 她就那樣靜靜地躺著,像睡著了一般胞谭。 火紅的嫁衣襯著肌膚如雪垃杖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天丈屹,我揣著相機(jī)與錄音调俘,去河邊找鬼伶棒。 笑死,一個胖子當(dāng)著我的面吹牛彩库,可吹牛的內(nèi)容都是我干的肤无。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼骇钦,長吁一口氣:“原來是場噩夢啊……” “哼宛渐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起眯搭,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤窥翩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鳞仙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寇蚊,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年棍好,在試婚紗的時候發(fā)現(xiàn)自己被綠了幔荒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡梳玫,死狀恐怖爹梁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情提澎,我是刑警寧澤姚垃,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站盼忌,受9級特大地震影響积糯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谦纱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一看成、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跨嘉,春花似錦川慌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亮瓷,卻和暖如春琴拧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嘱支。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工蚓胸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挣饥,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓沛膳,卻偏偏與公主長得像扔枫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子于置,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

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