![](/img/trans.png)
[英]How exactly works Spring Security configuration in this Spring Boot project?
[英]How exactly works this Spring Security example?
我是Spring Security的新手,我對在教程中找到的配置有些懷疑。
這是用於Spring Security配置到項目中的spring-security.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http>
<security:intercept-url pattern="/springLogin" access="permitAll"/>
<security:intercept-url pattern="/doSpringLogin" access="permitAll"/>
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/springHome" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/products" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/springLogout" access="permitAll"/>
<security:intercept-url pattern="/springLogin?error=true" access="permitAll"/>
<security:form-login login-page="/springLogin" login-processing-url="/doSpringLogin"
default-target-url="/springHome" authentication-failure-url="/springLogin?error=true"
username-parameter="username" password-parameter="password"
/>
<security:csrf disabled="true"/>
<security:logout logout-url="/springLogout" logout-success-url="/springLogin"/>
</security:http>
<bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>
<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsServiceImpl"></property>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg name="providers">
<list>
<ref bean="authenticationProvider"/>
</list>
</constructor-arg>
</bean>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsServiceImpl">
<security:password-encoder hash="plaintext"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
</beans>
我把它分成了一些部分。 第一個是 標簽內容。
它包含以下內容:
<security:intercept-url pattern="/springLogin" access="permitAll"/>
我認為這意味着每個人都可以訪問與/ springLogin資源相關的頁面
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
表示與/ myprofile資源相關的資源只能由設置了ROLE_USER角色的已記錄用戶(主體) 訪問 。
這個推理是否正確?
然后在之前的配置文件中有:
1) authenticationManager bean的聲明:
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg name="providers">
<list>
<ref bean="authenticationProvider"/>
</list>
</constructor-arg>
</bean>
我認為Spring使用它來使用Principal對象(例如Web應用程序的所有用戶)和Authorities (特定Principal可以執行的操作)填充SecurityContext 。
這個推理是否正確?
此對象將構造函數arg作為必須提供Principal信息的autentication提供者 bean的列表(例如,與特定Principal關聯的角色)
在這種情況下,提供了一個DaoAuthenticationProvider類的實現,它將name =“userDetailsService”的bean作為屬性,這個:
<bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>
這是UserDetailsServiceImpl類的一個實例,這個類:
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
System.out.println(username);
User user = RegisteryDAO.getUserDAO().getUserByUsername(username);
if(user == null){
return null;
}
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(user.getRole()));
UserDetails userDetails = new org.springframework.security.core.userdetails.
User(user.getUsername(), user.getPassword(), true, true, true, true, authorities);
return userDetails;
}
}
究竟發生了什么?
使用調試器在我看來,當用戶嘗試訪問特定頁面時,此loadUserByUsername()返回與記錄用戶相關的UserDetails對象,該對象包含表示與特定登錄用戶關聯的角色的List (例如,之前的ROLE_USER )
然后我認為Spring會自動使用
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
檢查用戶是否已將propper角色設置到上一個List列表中。
如果它已經將請求轉發到處理此Http請求的控制器方法,否則避免此HttpRequest來到此控制器方法並顯示一個頁面,表明用戶無法訪問此資源。
以下是您要詢問的一些概念和問題的解釋。
AuthenticationManager
AuthenticationManager
是負責處理Authentication
請求的組件。 對於用戶名/密碼登錄,身份驗證請求可能是UsernamePasswordAuthenticationToken
實例。
對於其他實現,請查看Authentication
JavaDoc 。
AuthenticationManager
還具有AuthenticationProvider
實現的集合。 這些組件能夠處理特定的Authentication
類型,並且AuthenticationManager
通過它們迭代嘗試找到能夠處理傳遞給它的Authentication
。 如果找到一個,則在顯示Authentication
對象的情況下調用它,如果成功則返回完全填充的Authentication
對象(否則拋出AuthenticationException
)。
AuthenticationProvider
如上所述, AuthenticationProvider
處理某種類型的Authentication
請求。 例如,當AuthenticationManager
調用時, DaoAuthenticationProvider
將執行以下步驟:
UsernamePasswordAuthenticationToken
UserDetailsService
服務實現(在您的情況下是UserDetailServiceImpl
)來按用戶名查找用戶 PasswordEncoder
和SaltSource
檢查用戶身份驗證令牌中提供的PasswordEncoder
。 UsernamePasswordAuthenticationToken
),其中包含主體,憑據並標記為已authenticated
AuthenticationException
您正在使用的DaoAuthenticationProvider
能夠處理UsernamePasswordAuthenticationToken
請求。 因此通常會形成登錄,等等。 您可以通過查看其supports()
方法實現來查看哪些類型的身份驗證提供程序支持,在DaoAuthenticationProvider
情況下如下所示:
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
現在讓我們看一下Spring Security文檔定義的Security過濾器鏈:
過濾器在鏈中定義的順序非常重要。 無論您實際使用哪種過濾器,訂單應如下:
ChannelProcessingFilter
,因為它可能需要重定向到不同的協議
SecurityContextPersistenceFilter
,因此可以在Web請求開始時在SecurityContextHolder中設置SecurityContext,並且當Web請求結束時(可以使用下一個Web請求准備好),可以將對SecurityContext的任何更改復制到HttpSession。
ConcurrentSessionFilter
,因為它使用SecurityContextHolder功能但需要更新SessionRegistry以反映來自主體的持續請求身份驗證處理機制 -
UsernamePasswordAuthenticationFilter
,CasAuthenticationFilter
,BasicAuthenticationFilter
等 - 以便可以修改SecurityContextHolder
以包含有效的身份驗證請求令牌
The SecurityContextHolderAwareRequestFilter
,如果您使用它將Spring安全感知HttpServletRequestWrapper安裝到您的servlet容器中
RememberMeAuthenticationFilter
,這樣如果沒有早期的身份驗證處理機制更新了SecurityContextHolder,並且請求提供了一個啟用記住我服務的cookie,那么一個合適的記憶身份驗證對象將放在那里
AnonymousAuthenticationFilter
,這樣如果沒有早期的身份驗證處理機制更新SecurityContextHolder,那么匿名身份驗證對象將被放在那里
ExceptionTranslationFilter
,用於捕獲任何Spring Security異常,以便可以返回HTTP錯誤響應或啟動相應的AuthenticationEntryPoint
FilterSecurityInterceptor
,用於保護Web URI並在拒絕訪問時引發異常
當用戶提交登錄表單時,將在過濾器鏈中的步驟4中調用AuthenticationManager
。 在表單登錄的情況下,它將由UsernamePasswordAuthenticationFilter
處理,它調用AuthenticationManager
來處理身份驗證:
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// ...
return this.getAuthenticationManager().authenticate(authRequest);
}
使用調試器在我看來,當用戶嘗試訪問特定頁面時,此
loadUserByUsername()
返回UserDetails
實際上,在用戶進行身份驗證時會調用loadUserByUsername()
,例如在提交登錄表單之后。 如果用戶已經過身份驗證,則不會調用此用戶。
我認為這意味着每個人都可以訪問與
/springLogin
資源相關的頁面:<security:intercept-url pattern="/springLogin" access="permitAll" />
然后我認為Spring將自動使用以下內容來檢查用戶是否具有適當的角色:
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')" />
正確。 此過程由FilterSecurityInterceptor
處理,它擴展了AbstractSecurityInterceptor
- 處理授權的核心Spring Security組件。 如果用戶未經過身份驗證或沒有所需的角色,則ExceptionTranslationFilter會拋出並處理ExceptionTranslationFilter
。 此過濾器處理安全性異常。 例如,在認證失敗的情況下,它將用戶重定向到認證入口點,例如登錄頁面。
Spring Security的內部體系結構在參考文檔中有很好的描述。 我建議看看它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.