SpringBoot日記——Spring的安全配置-登陸認證與受權

  安全是每一個項目開發中都須要考慮的,好比權限控制,安全認證,防止漏洞攻擊等。html

  比較常見的安全框架有:Apache的shiro、Spring Security等等,相信用shiro的用戶羣體更多,而security功能更多一些。html5

  那麼咱們就來看看Spring本身的Security是如何使用的。關於shiro後邊必定會有其餘文章補充的~。java

  官方文檔-入門連接web

Spring Security環境搭建

  1)、首先咱們要有一個能夠用來作測試的頁面,否則作了權限控制也不知道有沒有效果,那麼我下邊簡單的列一個登錄頁。不會寫的童鞋能夠直接拿去用:spring

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
<h1 align="center">歡迎光臨瓦爾哈拉-衆神管理系統</h1>
<h2 align="center">凡人,若是想查看衆神系統 <a th:href="@{/login}">請登記</a></h2>
<hr>

<h3>巨人族</h3>
<ul>
    <li><a th:href="@{/level1/1}">伊米爾</a></li>
    <li><a th:href="@{/level1/2}">蒂阿茲</a></li>
    <li><a th:href="@{/level1/3}">斯卡娣</a></li>
</ul>

<h3>其餘神祗</h3>
<ul>
    <li><a th:href="@{/level2/1}">女神格歐費茵</a></li>
    <li><a th:href="@{/level2/2}">瓦利</a></li>
    <li><a th:href="@{/level2/3}">林德</a></li>
</ul>

<h3>主神</h3>
<ul>
    <li><a th:href="@{/level3/1}">奧丁</a></li>
    <li><a th:href="@{/level3/2}">弗麗嘉</a></li>
    <li><a th:href="@{/level3/3}">索爾</a></li>
</ul>

</body>
</html>
welcome.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1 align="center">歡迎登錄瓦爾哈拉-衆神管理系統</h1>
    <hr>
    <div align="center">
        <form action="" method="post">
            用戶名:<input name=""/><br>
            口令:<input name=""><br/>
            <input type="submit" value="登錄">
        </form>
    </div>
</body>
</html>
login.html

  level-1數據庫

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
<a th:href="@{/}">返回</a>
<h1>伊米爾</h1>
<p>遠古洪荒時代,太虛混沌世界的中間有一條寬大無底的的金伽儂裂縫,冷、熱氣,火焰、冰塊、煙霧和蒸汽相互做用在裂縫邊緣造成了壅堵化成了巨人伊米爾。
    伊米爾的後代奧丁、維利和威長大後殺死了伊米爾,用他的軀體造成了世界:血化成湖泊海洋;肉化爲土地;骨頭化爲山;牙齒化爲岩石;
    腦髓化爲雲;頭蓋骨化爲天空;眉毛化爲一道柵欄。</p>
</body>
</html>
1.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
<a th:href="@{/}">返回</a>
<h1>蒂阿茲</h1>
<p>巨人斯卡娣的父親。蒂阿茲綁架了掌管永葆青春的金蘋果女神伊敦恩。由於這是洛基私約伊敦恩外出闖的禍,衆神祗便勒令洛基前去搭救。
    洛基借用弗麗嘉的羽衣變成一隻小鷹,潛入巨人蒂阿茲的城堡,將伊敦恩變成一枚核桃,銜在嘴裏飛向阿斯加爾德。
    不料被斯卡娣發現,蒂阿茲聞訊變成一隻隼鷹追遇上來。在即將追上之際,提爾點燃火把,將隼鷹燒死,巨人蒂阿茲便損命。</p>
</body>
</html>
2.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
<a th:href="@{/}">返回</a>
<h1>斯卡娣</h1>
<p>蒂阿茲之女、瓦尼爾部落主神尼奧爾德之妻。
    父親蒂阿茲被衆神設計殺害後,斯卡娣向主神奧丁要求血案賠償,奧丁無奈允諾她能夠在衆神祗中物色一位丈夫,
    斯卡娣看中了光明神巴德爾,奧丁天然不肯,遂略施手腕把斯卡娣嫁給了年老貌醜的海神尼奧爾德。
    斯卡娣嫁給尼奧爾德不久隨即離婚。</p>
</body>
</html>
3.html

  level2/3的本身根據level-1裏邊的類直接複製粘貼吧,基本都同樣的,把名字和內容改掉區分一下就好了,頁面的架構以下,放進resource-templates裏邊,這個都知道吧~安全

  好,咱們經過啓動主程序,來訪問一下咱們的頁面~(別忘了controller,否則你啓動也訪問不到頁面),訪問:localhost:8080架構

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Controller
public class ValhallaController {
    private final String PREFIX = "pages/";

    /**
     * 歡迎頁
     *
     * @return
     */
    @GetMapping("/")
    public String index() {
        return "welcome";
    }

    /**
     * 登錄頁
     *
     * @return
     */
    @GetMapping("/userlogin")
    public String loginPage() {
        return PREFIX + "login";
    }


    /**
     * level1頁面映射
     *
     * @param path
     * @return
     */
    @GetMapping("/level1/{path}")
    public String level1(@PathVariable("path") String path) {
        return PREFIX + "level1/" + path;
    }

    /**
     * level2頁面映射
     *
     * @param path
     * @return
     */
    @GetMapping("/level2/{path}")
    public String level2(@PathVariable("path") String path) {
        return PREFIX + "level2/" + path;
    }

    /**
     * level3頁面映射
     *
     * @param path
     * @return
     */
    @GetMapping("/level3/{path}")
    public String level3(@PathVariable("path") String path) {
        return PREFIX + "level3/" + path;
    }


}
ValhallaController.java

  看來訪問的仍是比較成功的。app

關於登陸的「認證」和「受權」

  1)、引入Spring Security模塊框架

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
  </dependency>

  2)、配置,這裏就須要使用一些註解了 @EnableWebSecurity

  咱們先這樣,將咱們須要受權的規則頁和對應的用戶等級進行匹配。而後訪問一下頁面看看,好比咱們點擊上圖中巨人族的 伊米爾(你會發現,它提示咱們403,訪問拒絕)

@EnableWebSecurity
public class MySercurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // super.configure(http);
        // 定製請求受權的規則
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("VIP1")
                .antMatchers("/level2/**").hasRole("VIP2")
                .antMatchers("/level3/**").hasRole("VIP3");
    }
}

  這是由於咱們尚未登陸訪問,做爲遊客,確定是不匹配咱們上邊寫的規則的,因此接下來,先解決非等級的一個跳轉

  加入以下的這段代碼,讓它爲咱們自動配置,只要不符合等級規則,就跳轉到/login的登陸頁(一樣點擊伊米爾再看)

        // 開啓自動配置的登陸功能,
        http.formLogin();

  3)、認證的規則設定

  講咱們擁有的用戶信息對應匹配規則,而後使用這些帳戶登陸試一下~(這裏爲了簡單說明,我用的是內存保存,固然,可使用「auth.jdbc.....」來進行數據庫的連接使用)

    // 自定義認證規則
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        super.configure(auth);
        auth.inMemoryAuthentication().withUser("human").password("123456").roles("VIP1")
                            .and()
                            .withUser("angle").password("123456").roles("VIP1", "VIP2")
                             .and()
                            .withUser("god").password("123456").roles("VIP1", "VIP2", "VIP3");
    }

  當咱們再次訪問,而且用上邊匹配的用戶登陸的時候卻發現這樣一個問題,說咱們的密碼id是空(There is no PasswordEncoder mapped for the id "null"),這是因爲spring security5.0+的版本,多一個密碼存儲格式官方指定的格式是:「{id}.....」,這個id就是加密方式,id能夠是bcrypt、sha256等,後面跟着的是加密後的密碼。官方推薦的事bcrypt的加密方式。以下:(若是你使用的jdbc的方式,那麼在存儲的時候就已經以這種方式存儲了,只須要在密碼上寫入就行了)

    // 自定義認證規則
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        super.configure(auth);
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("human").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP1")
                .and()
                .withUser("angle").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP1", "VIP2")
                .and()
                .withUser("god").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP1", "VIP2", "VIP3");
    }

  咱們再次登陸就正常了。

  3)、註銷功能

  咱們有了用戶的登陸,固然是須要一個註銷,也就是退出登陸的功能,這個功能就比較簡單了,只須要在上邊的代碼中加入一段以下的戲份就能夠實現了。

    1.在welcome.html中加入註銷按鈕的相關信息;

    2.在MySecurity的configure中加入註銷方法;

<!-- 把這段代碼放到你想要的位置,好比登陸前邊 -->
<
form th:action="@{/logout}" method="post"> <input type="submit" value="註銷"> </form>
  .....
  // 開啓自動配置的登陸功能,
  http.formLogin();   // 開啓自動配置的註銷功能,若是註銷成功返回「/」頁   http.logout().logoutSuccessUrl("/");

   4)、優化頁面的展現

  讓不一樣用戶看到首頁展現不一樣,沒有登陸的呢,就看不到具體內容。

    1.在pom裏邊引入springsecurity4;

    2.在html中改造一下,引入springsecurity4(加兩個div作判斷是否受權-sec:authorize),若是沒有認證(!isAuthenticated())就展現遊客請登陸,若是認證了就展現角色信息;讀取角色信息(sec:authentication);

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<body>
<h1 align="center">歡迎光臨瓦爾哈拉-衆神管理系統</h1>
<div sec:authorize="!isAuthenticated()">
    <h2 align="center">凡人,若是想查看衆神系統 <a th:href="@{/login}">請登陸</a></h2>
</div>
<div sec:authorize="isAuthenticated()">
    <h2><span sec:authentication="name"></span>,您好,您的角色有:
        <span sec:authentication="principal.authorities"></span></h2>
    <form th:action="@{/logout}" method="post">
        <input type="submit" value="註銷"/>
    </form>
</div>

<hr>

<div sec:authorize="hasRole('VIP1')">
    <h3>巨人族</h3>
    <ul>
        <li><a th:href="@{/level1/1}">依米爾</a></li>
        <li><a th:href="@{/level1/2}">蒂阿茲</a></li>
        <li><a th:href="@{/level1/3}">斯卡蒂</a></li>
    </ul>
</div>

<div sec:authorize="hasRole('VIP2')">
    <h3>其餘...</h3>
...
</div>

<div sec:authorize="hasRole('VIP3')">
    <h3>...</h3>
...
</div>

 

  再次訪問頁面,就會看到差異了:(截圖是登陸成功的)

   5)、完善功能。(綠色加粗部分就是新添的代碼)

    1.【MySecurityConfig】登陸通常都會有「記住我」這個功能,因此要加入remember me;

    2.【config+login】登陸請求變爲login,並進入到咱們本身的登陸頁,並將用戶名和密碼作關聯;

    3.【welcome.html】優化,將登陸請求變成userlogin請求;

                .antMatchers("/level3/**").hasRole("VIP3");
        http.formLogin().usernameParameter("user").passwordParameter("pwd").loginPage("/userlogin");
 http.rememberMe().rememberMeParameter("remember");         http.logout().logoutSuccessUrl("/");
<div align="center">
    <form th:action="@{/userlogin}" method="post">
        用戶名:<input name="user"/><br>
        密碼:<input name="pwd"><br/>
 <input type="checkbox" name="remember">記住我<br/>         <input type="submit" value="登錄">
    </form>
</div>
<div sec:authorize="!isAuthenticated()">
    <h2 align="center">凡人,若是想查看衆神系統 <a th:href="@{/userlogin}">請登陸</a></h2>
</div>

  

  以上,咱們來訪問一下看看本身的登陸系統吧~

相關文章
相關標籤/搜索