Spring Security(二) —— Guides

摘要: 原創出處 https://www.cnkirito.moe/spring-security-2/ 「老徐」歡迎轉載,保留摘要,謝謝!html



上一篇文章《Spring Security(一)–Architecture Overview》,咱們介紹了Spring Security的基礎架構,這一節咱們經過Spring官方給出的一個guides例子,來了解Spring Security是如何保護咱們的應用的,以後會對進行一個解讀。前端

2 Spring Security Guides

2.1 引入依賴

 1 <dependencies>
 2     <dependency>
 3         <groupId>org.springframework.boot</groupId>
 4         <artifactId>spring-boot-starter-web</artifactId>
 5     </dependency>
 6     <dependency>
 7         <groupId>org.springframework.boot</groupId>
 8         <artifactId>spring-boot-starter-security</artifactId>
 9     </dependency>
10     <dependency>
11         <groupId>org.springframework.boot</groupId>
12         <artifactId>spring-boot-starter-thymeleaf</artifactId>
13     </dependency>
14 </dependencies>

 

2.2 建立一個不受安全限制的web應用因爲咱們集成了springboot,因此不須要顯示的引入Spring Security文檔中描述core,config依賴,只須要引入spring-boot-starter-security便可。web

這是一個首頁,不受安全限制spring

src/main/resources/templates/home.html數據庫

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
 3     <head>
 4         <title>Spring Security Example</title>
 5     </head>
 6     <body>
 7         <h1>Welcome!</h1>
 8 
 9         <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
10     </body>
11 </html>

 

src/main/resources/templates/hello.html這個簡單的頁面上包含了一個連接,跳轉到」/hello」。對應以下的頁面安全

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
 3       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
 4     <head>
 5         <title>Hello World!</title>
 6     </head>
 7     <body>
 8         <h1>Hello world!</h1>
 9     </body>
10 </html>

 

 1 @Configuration
 2 public class MvcConfig extends WebMvcConfigurerAdapter {
 3 
 4     @Override
 5     public void addViewControllers(ViewControllerRegistry registry) {
 6         registry.addViewController("/home").setViewName("home");
 7         registry.addViewController("/").setViewName("home");
 8         registry.addViewController("/hello").setViewName("hello");
 9         registry.addViewController("/login").setViewName("login");
10     }
11 
12 }

 

2.3 配置Spring Security接下來配置Spring MVC,使得咱們可以訪問到頁面。springboot

一個典型的安全配置以下所示:架構

 1 @Configuration
 2 @EnableWebSecurity <1>
 3 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { <1>
 4     @Override
 5     protected void configure(HttpSecurity http) throws Exception {
 6         http <2>
 7             .authorizeRequests()
 8                 .antMatchers("/", "/home").permitAll()
 9                 .anyRequest().authenticated()
10                 .and()
11             .formLogin()
12                 .loginPage("/login")
13                 .permitAll()
14                 .and()
15             .logout()
16                 .permitAll();
17     }
18 
19     @Autowired
20     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
21         auth <3>
22             .inMemoryAuthentication()
23                 .withUser("admin").password("admin").roles("USER");
24     }
25 }

 

<2> configure(HttpSecurity)定義了哪些URL路徑應該被攔截,如字面意思所描述:」/「, 「/home」容許全部人訪問,」/login」做爲登陸入口,也被容許訪問,而剩下的」/hello」則須要登錄後才能夠訪問。<1> @EnableWebSecurity註解使得SpringMVC集成了Spring Security的web安全支持。另外,WebSecurityConfig配置類同時集成了WebSecurityConfigurerAdapter,重寫了其中的特定方法,用於自定義Spring Security配置。整個Spring Security的工做量,其實都是集中在該配置類,不單單是這個guides,實際項目中也是如此。併發

<3> configureGlobal(AuthenticationManagerBuilder)在內存中配置一個用戶,admin/admin分別是用戶名和密碼,這個用戶擁有USER角色。app

咱們目前尚未登陸頁面,下面建立登陸頁面:

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
 3       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
 4     <head>
 5         <title>Spring Security Example </title>
 6     </head>
 7     <body>
 8         <div th:if="${param.error}">
 9             Invalid username and password.
10         </div>
11         <div th:if="${param.logout}">
12             You have been logged out.
13         </div>
14         <form th:action="@{/login}" method="post">
15             <div><label> User Name : <input type="text" name="username"/> </label></div>
16             <div><label> Password: <input type="password" name="password"/> </label></div>
17             <div><input type="submit" value="Sign In"/></div>
18         </form>
19     </body>
20 </html>

 

最後,咱們爲hello.html添加一些內容,用於展現用戶信息。這個Thymeleaf模板提供了一個用於提交用戶名和密碼的表單,其中name=」username」,name=」password」是默認的表單值,併發送到「/ login」。 在默認配置中,Spring Security提供了一個攔截該請求並驗證用戶的過濾器。 若是驗證失敗,該頁面將重定向到「/ login?error」,並顯示相應的錯誤消息。 當用戶選擇註銷,請求會被髮送到「/ login?logout」。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="Sign Out"/>
        </form>
    </body>
</html>

 

2.4 添加啓動類咱們使用Spring Security以後,HttpServletRequest#getRemoteUser()能夠用來獲取用戶名。 登出請求將被髮送到「/ logout」。 成功註銷後,會將用戶重定向到「/ login?logout」。

@SpringBootApplication
public class Application {

    public static void main(String[] args) throws Throwable {
        SpringApplication.run(Application.class, args);
    }

}

 

訪問首頁http://localhost:8080/:2.5 測試

home.htmlhome.html

點擊here,嘗試訪問受限的頁面:/hello,因爲未登陸,結果被強制跳轉到登陸也/login

login.htmllogin.html

輸入正確的用戶名和密碼以後,跳轉到以前想要訪問的/hello:

hello.htmlhello.html

點擊Sign out退出按鈕,訪問:/logout,回到登陸頁面:

logout.htmllogout.html

 

Spring Security 沒法登錄,報錯:There is no PasswordEncoder mapped for the id 「null」

網上百度了一下發現這是由於Spring security 5.0中新增了多種加密方式,也改變了密碼的格式。

 

要想咱們的項目還可以正常登錄,須要修改一下configure中的代碼。咱們要將前端傳過來的密碼進行某種方式加密,spring security 官方推薦的是使用bcrypt加密方式。那麼如何對密碼加密呢,只須要在configure方法裏面指定一下。

修改後是這樣的:

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//inMemoryAuthentication 從內存中獲取 
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("user1").password(new BCryptPasswordEncoder().encode("123456")).roles("USER");
}


在inMemoryAuthentication()後面多了".passwordEncoder(new BCryptPasswordEncoder())",這至關於登錄時用BCrypt加密方式對用戶密碼進行處理。之前的".password("123456")" 變成了 ".password(new BCryptPasswordEncoder().encode("123456"))" ,這至關於對內存中的密碼進行Bcrypt編碼加密。比對時一致,說明密碼正確,容許登錄。

若是你如今用的也是從內存中取密碼,那麼按照上面這麼修改後應該會成功登陸沒有問題的。

若是你用的是在數據庫中存儲用戶名和密碼,那麼通常是要在用戶註冊時就使用BCrypt編碼將用戶密碼加密處理後存儲在數據庫中。而且修改configure()方法,加入".passwordEncoder(new BCryptPasswordEncoder())",保證用戶登陸時使用bcrypt對密碼進行處理再與數據庫中的密碼比對。以下:

//注入userDetailsService的實現類
auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
相關文章
相關標籤/搜索