Spring Security 入門—內存用戶驗證


簡介

作為 Spring 全家桶組件之一,Spring Security 是一個提供安全機制的組件,它主要解決兩個問題:

  • 認證:驗證用戶名和密碼;
  • 授權:對於不同的 URL 權限不一樣,只有當認證的用戶擁有某個 URL 的需要的權限時才能訪問。

Spring Security 底層使用的是過濾器,針對 URL 進行的攔截,對應到 Java 中也就是類; 因此被稱為粗粒度授權驗證,就是驗證 URL ,當前用戶是否有這個 URL 的權限。

入門

創建項目

使用 Idea 創建 Spring Boot 項目,勾選需要的組件:

  • Spring Web
  • Spring Security

或者創建項目后添加依賴:

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

這里使用的是 JSP 作為模板,有關如何在 Spring Boot 中使用 JSP 作為模板請訪問:https://www.cnblogs.com/cloudfloating/p/11787222.html

WebSecurityConfig

package top.cloudli.demo.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        
        auth.inMemoryAuthentication()
                .passwordEncoder(encoder)
                .withUser("root")
                .password(encoder.encode("root@123456"))
                .roles("ROOT", "USER")
                .and()
                .withUser("user")
                .password(encoder.encode("user@123456"))
                .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/css/**")
                .permitAll()        // css 不用驗證
                .anyRequest()
                .authenticated()    // 其它頁面全部需要驗證
                .and()
                .formLogin()        // 使用默認登錄頁面
                .and()
                .exceptionHandling()
                .accessDeniedPage("/401")   // 無權限時跳轉的頁面
                .and()
                .logout();
    }
}
  • @EnableWebSecurity 注解啟用驗證;
  • @EnableGlobalMethodSecurity(prePostEnabled=true) 注解允許我們在控制器的方法中使用 @PreAuthorize 實現權限分割。

此處創建了兩個用戶並保存在內存中,分別是擁有 ROOT 和 USER 權限的 root 用戶和僅擁有 USER 權限的 user 用戶。

fromLogin() 方法可以接着調用 loginPage() 指定一個自定義登錄頁面,這里使用的是默認登錄頁面。

編寫頁面

1.index.jsp,所有通過驗證的用戶都可以訪問:

<%--
  任何通過驗證的用戶都能訪問的頁面
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Spring Security Demo Application</title>
    <link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="content">
    <h1>Spring Security In Memory Authentication</h1>
    <h2>這是被保護的頁面(ROLE_USER)。</h2>
</div>
</body>
</html>

2.root.jsp,只有擁有 ROOT 權限的用戶能訪問:

<%--
  需要 ROLE_ROOT 才能訪問的頁面
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Root Page</title>
    <link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="content">
    <h1>Root Page</h1>
    <h2>你正在訪問受保護的頁面(ROLE_ROOT)。</h2>
</div>
</body>
</html>

3.401.jsp,沒有權限時跳轉的頁面:

<%--
  權限不夠時跳轉的頁面
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>401 Unauthorized</title>
    <link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body class="error">
<div class="content">
    <h1>401 Unauthorized!</h1>
    <h2>你沒有權限訪問此頁面。</h2>
</div>
</body>
</html>

控制器

package top.cloudli.demo.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class DemoController {

    @PreAuthorize("hasAnyAuthority('ROLE_USER')")
    @GetMapping("/")
    public String index() {
        return "index";
    }

    @PreAuthorize("hasAnyAuthority('ROLE_ROOT')")
    @GetMapping("/root")
    public String root() {
        return "root";
    }

    @GetMapping("/401")
    public String accessDenied() {
        return "401";
    }
}

@PreAuthorize 注解指定了訪問頁面所需要的權限,這里的權限要加上 ROLE_ 前綴。

Run

訪問 http://localhost:8080/ 將進入登錄頁面(這里使用的是 Spring Security 的默認登錄頁面):

image

使用剛才創建的內存用戶 user 登錄后將返回 index 頁面:

image

訪問 http://localhost:8080/root,由於 user 用戶沒有 ROLE_ROOT 權限,跳轉到 401 頁面:

image

訪問 http://localhost:8080/logout 將進入默認登出頁面:

image

這里的登錄和登出頁面均可以使用自定義頁面,只需要在自定義的頁面中把數據通過 PSOT 請求提交到 /login/logout 即可完成登錄和登出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM