1. 程式人生 > >01-Spring Security框架學習

01-Spring Security框架學習

01-Spring Security框架學習

簡介

Spring Security 是什麼

Spring Security 為基於 Java EE 的企業應用提供綜合的安全服務。尤其支援使用Spring Framework構建的專案,這是目前企業軟體開發的流行的Java EE解決方案。

Spring Security 解決那些問題

Java EE Servlet 規範或 EJB 規範的安全特性在典型的企業應用場景中缺乏深度;在系統環境中做大量的重複配置工作(例:判斷使用者是否登入,是否具備管理員的許可權等)。

一般來說,Web 應用的安全性包括使用者認證(Authentication)和使用者授權(Authorization)兩個部分。使用者認證指的是驗證某個使用者是否為系統中的合法主體,也就是說使用者能否訪問該系統。使用者認證一般要求使用者提供使用者名稱和密碼。系統通過校驗使用者名稱和密碼來完成認證過程。使用者授權指的是驗證某個使用者是否有許可權執行某個操作。在一個系統中,不同使用者所具有的許可權是不同的。比如對一個檔案來說,有的使用者只能進行讀取,而有的使用者可以進行修改。一般來說,系統會為不同的使用者分配不同的角色,而每個角色則對應一系列的許可權。這些概念非常通用,它們並不是 Spring Security 的特性。

Spring Security 的優點

認證級別

在認證級別,Spring Security 支援範圍廣泛的認證模型。大多數認證模型由第三方提供,或由相關標準制定組織(如 IETF)研製,同時Spring Security 提供它自己的認證功能。
- HTTP BASIC headers認證 (基於IETF RFC標準)
- HTTP Digest headers認證 (基於IETF RFC標準)
- HTTP X.509 客戶端證書交換 (基於IETF RFC標準)
- LDAP (一種非常常見的跨平臺認證需求,在大環境下尤甚)
- 基於表單的認證 (通常用於簡單的使用者需求)
- OpenID認證
- 基於預定義的請求頭進行認證 (諸如計算機叢集)
- JA-SIG 中央認證服務 (也稱為CAS, 是一種流行的開源的單點登陸系統)
- 為RMI 和 HttpInvoker(一種Spring遠端協議)提供對使用者透明的認證機制
- 自動的 “remember-me” 認證 (你可以勾選此選項,從而避免在一定時間內進行重複認證)
- 匿名認證 (為每個未經認證的使用者提供一個特殊的安全身份)
- Run-as 認證 (同一個呼叫需要進行不同的安全校驗時非常有用)
- Java認證與認證服務 - Java Authentication and Authorization Service (JAAS)
- JEE
- 認證 (如果你需要,你仍然可以使用容器託管
- 認證)
- Kerberos
- Java開源單點登陸 - Java Open Source Single Sign On (JOSSO) *
- OpenNMS網路管理平臺 - OpenNMS Network Management Platform *
- AppFuse *
- AndroMDA *
- Mule ESB *
- Direct Web Request (DWR) *
- Grails *
- Tapestry *
- JTrac *
- Jasypt *
- Roller *
- Elastic Path *
- Atlassian Crowd *
- 你自己的許可權系統 (參見後續內容)

帶*表示由第三方提供

授權功能

Spring Security允許對授權功能進行深度設定。它關注於三個主要方面:web請求授權、方法呼叫授權以及域物件例項訪問授權

歷史背景

  • 2004年1月,已經大約有20人在使用此程式碼。這些首批使用者開始建議將其作為一個SourceForge專案,於是專案於2004年3月正式成立。
  • 2006年5月,1.0.0 final release版本正式釋出
  • 2007年年末的時候,正式成為Spring Portfolio官方專案,並更名為”Spring Security”。

Spring Security版本編號 MAJOR.MINOR.PATCH(主版本.小版本.補丁)
- MAJOR的變更意味著大規模的API的更新,因此很多地方都不會相容舊版本。
- MINOR的變更儘可能保持原始碼和編譯檔案的相容性,儘管可能有一些設計上的變更或者不相容的更新。
- PATCH通常完全向前向後相容,主要用於修復一些bug與缺陷。

Spring Security 的入門案例

基本步驟

  1. 建立Maven的web專案,在pom.xml中匯入依賴入下
<!-- spring-security 的依賴 -->
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-config</artifactId>
  <version>${spring.version}</version>
</dependency>
  1. web.xml 配置過濾器
<!-- 通過 ContextLoaderListener 定義 spring context 容器的xml檔案的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/*.xml
</param-value>
</context-param>

<!-- springSecurity 指定的過濾器: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>

<!-- web容器(監聽器)啟動載入容器上下文-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  1. 建立用於演示的頁面,src/main/webapp/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
spring-security,hello world!
歡迎來到,spring-security的世界!
</body>
</html>
  1. 新增Spring Security 的配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security.xsd">

  <!-- 頁面的連結規則 -->     
  <http use-expressions="false">
    <intercept-url pattern="/**" access="ROLE_ADMIN"/>
    <!-- 開啟表單提交功能 -->
    <form-login/>
  </http>
  <!-- 認證管理器 -->
  <authentication-manager>
    <authentication-provider>
      <user-service>
        <user name="admin" password="admin" authorities="ROLE_ADMIN"/>
      </user-service>
    </authentication-provider>
  </authentication-manager>
</beans:beans>

注意:該檔案是本案例的重點,基本內容使用註釋。
- 把security的頭資訊的配置作為了預設配置,那麼以後在進行編寫security的相關配置的時候就不需要字首。

執行效果

image

出現問題解決

  1. 出現java.lang.NoSuchMethodError: org.springframework.util.AntPathMatcher.setCaseSensitive(Z)V的錯誤,如下詳細錯誤資訊

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#0': Cannot resolve reference to bean 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0' while setting constructor argument with key [4]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter]: Constructor threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.util.AntPathMatcher.setCaseSensitive(Z)V
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:382)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:157)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:637)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:140)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1131)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1034)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
        ... 26 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter]: Constructor threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.util.AntPathMatcher.setCaseSensitive(Z)V
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1093)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1038)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
        ... 40 more
    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter]: Constructor threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.util.AntPathMatcher.setCaseSensitive(Z)V
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1086)
        ... 48 more
    Caused by: java.lang.NoSuchMethodError: org.springframework.util.AntPathMatcher.setCaseSensitive(Z)V
        at org.springframework.security.web.util.matcher.AntPathRequestMatcher$SpringAntMatcher.createMatcher(AntPathRequestMatcher.java:268)
        at org.springframework.security.web.util.matcher.AntPathRequestMatcher$SpringAntMatcher.<init>(AntPathRequestMatcher.java:252)
        at org.springframework.security.web.util.matcher.AntPathRequestMatcher$SpringAntMatcher.<init>(AntPathRequestMatcher.java:245)
        at org.springframework.security.web.util.matcher.AntPathRequestMatcher.<init>(AntPathRequestMatcher.java:116)
        at org.springframework.security.web.util.matcher.AntPathRequestMatcher.<init>(AntPathRequestMatcher.java:84)
        at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.<init>(UsernamePasswordAuthenticationFilter.java:62)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
        ... 50 more

    問題原因分析:

    由於AntPathMatcher的類的方法在setCaseSensitive()在Spring-core 4.1.X 中不存在導致.
    參考答案:

    1. ontext-initialization-failed-nosuchmethoderror-antpathmatcher-setcasesensiti

    問題解決方式
    修改Spring和Spring Security的版本到4.2.3.RELEASE

專案

[專案剛剛開始,後期上傳至Git倉庫共享]


參考資料
- Spring Security 參考手冊 Gitbook
- spring security中文教程講解 轉自 臨遠 部落格