權限管理與SpringSecurity

基於角色的權限管理

什麼是角色?

  • 代表一系列行爲或責任的實體
  • 限定能做什麼、不能做什麼
  • 用戶賬號往往與角色相關聯

我們在談到程序權限管理的話,能不能想到角色這一個概念,角色是代表了一系列行爲或者責任的實體,用於限制在系統中能做什麼,不能做什麼,一般來說,一個用戶的賬號在系統中能做什麼,往往取決於這個用戶是什麼角色,比如一個用戶他是一個項目管理員,他就能做這個項目管理員能做的事情,比如說,他可以查看項目中的應用,管理項目組中的成員,可以導出項目報表等等,所以說用戶的話關聯了角色之後,他就有了一相關角色的一些操作權限 ,所以,角色是一種行爲的概念,表示用戶能在系統中進行的一些操作。

RBAC

  • 基於角色的訪問控制(Role-Based Access Control)
  • 隱式訪問控制
	if(user.hasRole("Project Manager")){
		//顯示按鈕
	}else{
		//不顯示按鈕
	}

隱式訪問控制與角色是密切關聯的,假設角色名稱改變的話,代碼可能也要做相應的改變

  • 顯示訪問控制
	if(user.isPermitted("projectReport:view:12345")){
		//顯示按鈕
	}else{
		//不顯示按鈕
	}

與角色沒有直接關聯,而是判斷是否擁有某種權限,這個權限與角色關聯,用戶再和角色關聯。最終實現用戶與權限的關聯,這種方式相比隱式訪問控制,就比較靈活了。

權限管理解決方案

  • Apache Shiro
    Apache Shiro 相對於SpringSecurity來說,比較輕量級,使用起來比較簡單一些
  • Spring Security
    SpringSecurity在使用上來說比ApacheShiro功能更多一點、更強大一點。在Spring應用中,它是在兼容性以及在支持方面都比Shiro要好一點。Security整個社區也比較完善,發展上前景也比較好。

SpringSecurity 簡介

在JavaEE企業級應用中提供全面的安全服務,特別是在Spring應用中。SpringSecurity經常會做一些集成。SpringSecurity與Apache Shiro其實有很多的相似點。

核心領域概念

  • 認證(authentication):“認證” 是建立主體(principal)的過程。“主體”通常是指可以在應用程序中執行操作的用戶、設備或其他系統
  • 授權(authorization):或稱爲“訪問控制(accell-control)”,"授權"是指決定是否允許主體在應用程序中執行一些相關的操作。

身份驗證技術

  • HTTP BASIC
  • HTTP Digest
  • HTTP X.509
  • LDAP
  • 基於表單的認證
  • OpenID
  • 單點登錄
  • Remember-Me
  • 匿名身份驗證
  • Run-as
  • JAAS
  • JavaEE 容器認證

模塊

SpringSecurity是模塊化的

  • Core - spring-security-core.jar:包含認證,授權接口等等
  • Remoting- spring-security-remoting.jar
  • Web - spring-security-web.jar
  • Config - spring-security-config.jar : 配置
  • LDAP - spring-security-ldap.jar
  • ACL - spring-security-acl.jar
  • CAS - spring-security-cas.jar : 單點登錄
  • OpenID - spring-security-openid.jar
  • Test - spring-security-test.jar

SpringSecurity與SpringBoot集成

依賴

	<!-- springboot2.2.2 -->
	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
     </parent>
	
	<!-- springboot已經對thymeleaf做了集成,版本不用寫 -->
	<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        
	<!-- springboot已經對security做了集成,版本不用寫 -->
	 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

<!-- 官方並沒有對thymeleaf-extras-springsecurity做集成,所以要將此依賴引入進來 -->
	 <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

SpringSecurity實戰

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.giteasy</groupId>
    <artifactId>security-in-action</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>security-in-action</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

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

        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

創建安全配置類SecurityConfig.java

package cn.giteasy.bootstrap.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;

/**
 * 安全配置類
 * Created by Axin in 2019/12/23 21:46
 */
@EnableWebSecurity //啓用Security
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 自定義配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.authorizeRequests()
           .antMatchers("/css/**","/js/**","/fonts/**","/index").permitAll()//都可以訪問
           .antMatchers("/users/**").hasRole("ADMIN")//需要ADMIN的角色才能訪問
           .and()
           .formLogin()//基於form表單認證
           .loginPage("/login") //自定義登錄頁面
           .failureUrl("/login-error");//登錄失敗頁面
    }

    /**
     * 認證信息管理
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication()//爲了演示方便我們將認證信息存儲在內存中
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("axin") //用於演示的用戶名
                .password(new BCryptPasswordEncoder().encode("123456"))//密碼
                .roles("ADMIN");//角色名稱
    }
}

相應的Controller:MainController.java

package cn.giteasy.bootstrap.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 主頁控制器
 * Created by Axin in 2019/12/23 21:58
 */
@Controller
public class MainController {

    @GetMapping("/")
    public String root(){
        return "redirect:/index";
    }


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

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

    @GetMapping("/login-error")
    public String loginError(Model model){
        model.addAttribute("loginError",true);
        model.addAttribute("errorMsg","登錄失敗,用戶名或密碼錯誤!");
        //登錄失敗後,還是會返回登錄頁面,但是會攜帶錯誤信息
        return "login";
    }
}

前端頁面編寫:
這裏只提供了關鍵代碼,如果需要查看祥細代碼,文章結尾有github鏈接

公共header.html

添加命令空間:
<html data-th-fragment="header"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
		......
		......
		......
		......
		 <!--登錄判斷:如果已登錄,顯示用戶名和退出按鈕-->
            <div sec:authorize="isAuthenticated()" class="row">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item">
                      <span class="nav-link" sec:authentication="name"></span>
                    </li>
                </ul>
                <form action="/logout" th:action="@{/logout}" method="post">
                    <input class="btn btn-outline-success" type="submit" value="退出">
                </form>

            </div>
            <!--登錄判斷:如果未登錄,顯示登錄按鈕-->
            <div sec:authorize="isAnonymous()">
                <a href="/login" th:href="@{~/login}" class="btn btn-outline-success my-2 my-sm-0" type="submit">登錄</a>
            </div>

			...
			...
			...
</html>

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head th:replace="~{fragments/header :: header}">
    <!--th:replace="~{fragments/header :: header}":會將header.html頁面內容替換到這個dom節點下-->
</head>
<body>

<div class="container blog-content-container">

    <!--登錄判斷:如果已登錄,顯示用戶名和用戶角色-->
    <div sec:authorize="isAuthenticated()">
        <p>已登錄</p>
        <p>用戶名:<span sec:authentication="name"></span></p>
        <p>角  色:<span sec:authentication="principal.authorities"></span></p>
    </div>

    <!--登錄判斷:如果未登錄,提示未登錄信息-->
    <div sec:authorize="isAnonymous()">
        <p>未登錄</p>
    </div>

</div>
<div th:replace="~{fragments/footer :: footer}">...</div>
</body>
</html>

login.html

		...
		...
		...
	<!--
       /login: 我們並沒有在Controller中定義/login接口,
       而在SecurityConfig.java文件中定義了/login接口,
       security會自動攔截登錄請求進行匹配賬號和密碼 進行認證
    -->
    <form action="/login" method="POST" th:action="@{/login}">
        <h3>請登錄</h3>
        <div class="from-group col-md-5">
            <label for="username" class="col-form-label">賬號</label>
            <input type="text" class="form-control" id="username" name="username" maxlength="50" placeholder="請輸入賬號">
        </div>
        <div class="from-group col-md-5">
            <label for="password" class="col-form-label">密碼</label>
            <input type="text" class="form-control" id="password" name="password" maxlength="50" placeholder="請輸入密碼">
        </div>
        <div class="from-group col-md-5">
            <button type="submit" class="btn btn-primary">登錄</button>
        </div>
        
        <!--登錄失敗,重定向到此而面,顯示登錄失敗信息-->
        <div class="col-md-5" th:if="${loginError}">
            <p class="blog-label-error" th:text="${errorMsg}"></p>
        </div>
    </form>
		    ...
		    ...
		    ...
    

項目目錄結構,只標記關鍵文件
在這裏插入圖片描述
頁面效果

在這裏插入圖片描述
在這裏插入圖片描述

github:https://github.com/gitAxin/security-in-action.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章