Spring security基本使用


Spring security 學習記錄

1、Spring security 簡介

​ Spring Security 為 Java EE-based 企業軟件應用程序提供全面的安全服務(也就是用戶登錄頁面和相關權限的控制),應用的安全性包括用戶認證( Authentication )和用戶權限( Authorization )兩部分。 用戶認證是確定某個用戶是否有進入系統的權限,使用用戶名密碼去認證,也就是所謂的登錄;用戶權限是確定哪些用戶有哪些功能權限,一般都是按角色。

2、主要過濾器

​ 眾所周知 想要對對Web資源進行保護,最好的辦法莫過於Filter,要想對方法調用進行保護,最好的辦法莫過於AOP。所以springSecurity在我們進行用戶認證以及授予權限的時候,通過各種各樣的攔截器來控制權限的訪問,從而實現安全。

有篇關於過濾器的文章,有需要可以查看下

https://blog.csdn.net/andy_zhang2007/article/details/84726992

  • WebAsyncManagerIntegrationFilter

    為請求處理過程中可能發生的異步調用准備安全上下文獲取途徑

  • SecurityContextPersistenceFilter

    整個請求處理過程所需的安全上下文對象SecurityContext的准備和清理不管請求是否針對需要登錄才能訪問的頁面,這里都會確保SecurityContextHolder中出現一個SecurityContext對象:
    1.未登錄狀態訪問登錄保護頁面:空SecurityContext對象,所含Authentication為null
    2.登錄狀態訪問某個頁面:從SecurityContextRepository獲取的SecurityContext對象

  • HeaderWriterFilter

    將指定的頭部信息寫入響應對象

  • CorsFilter

    對請求進行csrf保護

  • LogoutFilter

    檢測用戶退出登錄請求並做相應退出登錄處理

  • RequestCacheAwareFilter

    提取請求緩存中緩存的請求
    1.請求緩存在安全機制啟動時指定
    2.請求寫入緩存在其他地方完成
    3.典型應用場景:
    用戶請求保護的頁面,
    系統引導用戶完成登錄認證,
    然后自動跳轉到到用戶最初請求頁面

  • SecurityContextHolderAwareRequestFilter

    包裝請求對象使之可以訪問SecurityContextHolder,從而使請求真正意義上擁有接口HttpServletRequest中定義的getUserPrincipal這種訪問安全信息的能力

  • AnonymousAuthenticationFilter

    如果當前SecurityContext屬性Authentication為null,將其替換為一個AnonymousAuthenticationToken`

  • SessionManagementFilter

    檢測從請求處理開始到目前是否有用戶登錄認證,如果有做相應的session管理,比如針對為新登錄用戶創建新的session(session fixation防護)和設置新的csrf token等。

  • ExceptionTranslationFilter

    處理AccessDeniedException和 AuthenticationException異常,將它們轉換成相應的HTTP響應

  • FilterSecurityInterceptor

    一個請求處理的安全處理過濾器鏈的最后一個,檢查用戶是否已經認證,如果未認證執行必要的認證,對目標資源的權限檢查,如果認證或者權限不足,拋出相應的異常:AccessDeniedException或者AuthenticationException

  • UsernamePasswordAuthenticationFilter

    檢測用戶名/密碼表單登錄認證請求並作相應認證處理:
    1.session管理,比如為新登錄用戶創建新session(session fixation防護)和設置新的csrf token等
    2.經過完全認證的Authentication對象設置到SecurityContextHolder中的SecurityContext上;
    3.發布登錄認證成功事件InteractiveAuthenticationSuccessEvent
    4.登錄認證成功時的Remember Me處理
    5.登錄認證成功時的頁面跳轉

  • BasicAuthenticationFilter 檢測和處理http basic認證

  • DefaultLoginPageGeneratingFilter 生成缺省的登錄頁面

  • DefaultLogoutPageGeneratingFilter 生成缺省的退出登錄頁面

  • RememberMeAuthenticationFilter 針對Remember Me登錄認證機制的處理邏輯 (免登陸)

3、security核心組件

  • SecurityContextHolder:提供對SecurityContext的訪問
  • SecurityContext,:持有Authentication對象和其他可能需要的信息
  • UsernamePasswordAuthenticationFilter 檢測用戶民密碼並做處理
  • AuthenticationManager 其中可以包含多個AuthenticationProvider
  • ProviderManager對象為AuthenticationManager接口的實現類
  • AuthenticationProvider 主要用來進行認證操作的類 調用其中的authenticate()方法去進行認證操作
  • Authentication:Spring Security方式的認證主體
  • GrantedAuthority:對認證主題的應用層面的授權,含當前用戶的權限信息,通常使用角色表示
  • UserDetails:構建Authentication對象必須的信息,可以自定義,可能需要訪問DB得到
  • UserDetailsService:通過username構建UserDetails對象,通過loadUserByUsername根據userName獲取UserDetail對象 (可以在這里基於自身業務進行自定義的實現 如通過數據庫,xml,緩存獲取等)
  • passwordEncoder 密碼加密器

4、主要流程

  1. 如圖:當用戶登錄時,前端將用戶輸入的用戶名、密碼信息傳輸到后台( UsernamePasswordAuthenticationFilter ),后台用一個類對象將其封裝起來,通常使用的是UsernamePasswordAuthenticationToken這個類,然后在 AuthenticationManager 中獲取用戶,進行加密,認證對比等相關操作,返回是否是系統用戶。

  2. 比較兩者的密碼,如果密碼正確就成功登陸,同時把包含着用戶的用戶名、密碼、所具有的權限等信息的類對象放到SecurityContextHolder(安全上下文容器,類似Session)中去。

  3. 用戶訪問一個資源的時候,首先判斷是否是受限資源。如果是的話還要判斷當前是否未登錄,沒有的話就跳到登錄頁面。

  4. 如果用戶已經登錄,訪問一個受限資源的時候,程序要根據url去數據庫中取出該資源所對應的所有可以訪問的角色,然后拿着當前用戶的所有角色一一對比,判斷用戶是否可以訪問。

  5. 用戶認證的實現方式有很多種,主要體現在 AuthenticationProvider 接口的實現中,目前主流的實現:

    DaoAuthenticationProvider 利用數據庫數據進行登錄認證

    JassAuthenticationProvider Java 認證和授權服務

    CasAuthenticationProvider 利用單點登錄進行登錄認證

    LdapAuthenticationProvider 跨域身份認證

5、簡單代碼實現

本例子是基於老版本3.2.7的XML一種實現,需要基於confirm配置,請查看更高版本,地址如下:

https://www.docs4dev.com/docs/zh/spring-security/4.2.10.RELEASE/reference

web.xml配置,添加springSecurityFilterChain配置

  <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Security.xml配置

具體配置講解可以參考

https://www.cnblogs.com/yyxxn/p/8080141.html

<sec:http pattern="/loggedOut.html" security="none" />
    <!-- 配置免登錄的資源 -->
	<sec:http pattern="/toLogin" security="none" />
	<sec:http pattern="/loginError" security="none" />
	<!-- IS_AUTHENTICATED_ANONYMOUSLY 允許匿名用戶進入 -->
	<!-- IS_AUTHENTICATED_FULLY 允許登錄用戶進入 -->
	<!-- IS_AUTHENTICATED_REMEMBERED 允許登錄用戶和rememberMe用戶進入 -->

   <!--auto-config = true 則使用from-login. 如果不使用該屬性 則默認為http-basic(沒有session).--> 
    <!-- lowercase-comparisons:表示URL比較前先轉為小寫。-->  
    <!-- path-type:表示使用Apache Ant的匹配模式。-->  
    <!--access-denied-page:訪問拒絕時轉向的頁面。-->  
    <!-- access-decision-manager-ref:指定了自定義的訪問策略管理器。-->  
    <!--isAuthenticated() 當前用戶是否已通過身份驗證-->
    <!--access="hasRole('SUPER_ADMIN') 代表該地址只有權限SUPER_ADMIN才能查看-->
	<sec:http use-expressions="true"  auto-config="true" >
		<sec:intercept-url pattern="/user/*" access="hasRole('SUPER_ADMIN')" />
		<sec:intercept-url pattern="/**" access="isAuthenticated()" />

        <!--login-page:指定登錄頁面。  -->  
<!-- login-processing-url:指定了客戶在登錄頁面中按下 Sign In 按鈕時要訪問的 URL。-->  
        <!-- authentication-failure-url:指定了身份驗證失敗時跳轉到的頁面。-->  
        <!-- default-target-url:指定了成功進行身份驗證和授權后默認呈現給用戶的頁面。-->  
<!-- always-use-default-target:指定了是否在身份驗證通過后總是跳轉到default-target-url屬性指定的URL。 
-->  
		<sec:form-login login-page="/toLogin"
						login-processing-url="/login"
						always-use-default-target="true"
						default-target-url="/index"
						authentication-failure-url="/toLogin?error=1"
		/>
		<!--logout-url:指定了用於響應退出系統請求的URL。其默認值為:/j_spring_security_logout。-->
		<!-- logout-success-url:退出系統后轉向的URL。-->
		<!-- invalidate-session:指定在退出系統時是否要銷毀Session。-->
		<sec:logout invalidate-session="true" logout-success-url="/toLogin"
					logout-url="/j_spring_cas_security_logout" />
		<!-- 實現免登陸驗證 -->
		<sec:remember-me />
	</sec:http>

	<bean id="myFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
		<property name="authenticationManager" ref="casAuthenticationManager" />
	</bean>

	<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"
		  p:userDetailsService-ref="userDetailsService" p:passwordEncoder-ref="md5PasswordEncoder">
	</bean>
<!--md5加密方式-->
	<bean id = "md5PasswordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></bean>

<!--數據使用直接查詢數據庫方式,也可以實現userDetailsService接口-->
	<bean id="casDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${JDBC.driverClassName}" />
		<property name="url" value="${JDBC.url}" />
		<property name="username" value="${JDBC.username}" />
		<property name="password" value="${JDBC.password}" />
	</bean>
	<sec:jdbc-user-service id="userDetailsService" data-source-ref="casDataSource"
						   users-by-username-query="
					SELECT
						u.account username,
						u.`password`,
						u.displayFlag enabled
					FROM
						core_user AS u
					WHERE
						u.displayFlag = 1
					AND
						u.enabledFlag = 1
					AND
						u.account = ? "
						   authorities-by-username-query="
					SELECT
						u.account username,
						r.`code` role
					FROM
						core_role AS r
					LEFT JOIN core_user_role AS ur ON r.id = ur.roleId
					INNER JOIN core_user AS u ON ur.userId = u.id
					WHERE
						u.displayFlag = 1
					AND
						u.enabledFlag = 1
					AND
						u.account = ?" />

login.jsp如下

<form id="fm1" action="/login" method="post" novalidate="novalidate">
			<div class="form-group form-username">
				<input type="text" class="form-control" id="username" name="j_username"  placeholder="Name">
			</div>
			<div class="form-group form-password">
				<input id="password" name="j_password"  type="password">
			</div>
			<div class="form-checkbox">
		  <span class="checkbox pointer checked">
		  <input type="checkbox" id="_spring_security_remember_me" name="_spring_security_remember_me" checked="checked">
		  </span>&nbsp;&nbsp;7天免登錄
			</div>
			<div class="form-group">
				<button type="submit" class="btn id="loginBtn">登 錄
				</button>
			</div>
		</form>

注意:如果是使用UsernamePasswordAuthenticationFilter ,得注意使用的版本,每個版本對應的字段可能不一樣,需要打開源碼看看。

在3.2.7中,用戶名(j_username),密碼(j_password),記住密碼(_spring_security_remember_me)。

在4.2中,用戶名(username),密碼(password)

在學習的過程中,借鑒了前輩們的文章,參考如下

https://blog.csdn.net/liushangzaibeijing/article/details/81220610

https://blog.csdn.net/andy_zhang2007/article/details/84726992

https://www.docs4dev.com/docs/zh/spring-security/4.2.10.RELEASE/reference


免責聲明!

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



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