Spring Security can participate in many different authentication environments. While we recommend people use Spring Security for authentication and not integrate with existing Container Managed Authentication, it is nevertheless supported - as is integrating with your own proprietary authentication system.html
Spring Security能夠參與許多不一樣的身份驗證環境。雖然咱們建議人們使用Spring Security進行身份驗證,而不是與現有的容器管理身份驗證集成,可是它仍然受到支持——就像與您本身的專有身份驗證系統集成同樣。web
Let’s consider a standard authentication scenario that everyone is familiar with.spring
1, A user is prompted to log in with a username and password.
2, The system (successfully) verifies that the password is correct for the username.
3, The context information for that user is obtained (their list of roles and so on).
4, A security context is established for the user
5, The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.小程序
讓咱們考慮一個每一個人都熟悉的標準身份驗證場景。緩存
1, 提示用戶使用用戶名和密碼登陸。
2, 系統(成功)驗證用戶名的密碼是否正確。
3, 獲取該用戶的上下文信息(角色列表等)。
4, 爲用戶創建一個安全上下文
5, 用戶繼續執行某些操做,這些操做可能受到訪問控制機制的保護,該機制根據當前安全上下文信息檢查操做所需的權限。安全
The first three items constitute the authentication process so we’ll take a look at how these take place within Spring Security.session
1, The username and password are obtained and combined into an instance of UsernamePasswordAuthenticationToken (an instance of the Authentication interface, which we saw earlier).
2, The token is passed to an instance of AuthenticationManager for validation.
3, The AuthenticationManager returns a fully populated Authentication instance on successful authentication.
4, The security context is established by calling SecurityContextHolder.getContext().setAuthentication(…), passing in the returned authentication object.less
前三項構成了身份驗證過程,所以咱們將瞭解這些在Spring Security中是如何發生的。ide
1, 用戶名和密碼被獲取並組合到UsernamePasswordAuthenticationToken的實例中(Authenticationinterface的實例,咱們在前面看到過)。
2, 令牌傳遞給AuthenticationManager的一個實例進行驗證。
3, AuthenticationManager在身份驗證成功時返回一個完整填充的身份驗證明例。
4, 安全上下文是經過調用securitycontext.getcontext().setauthentication(…),傳入返回的身份驗證對象來創建的。ui
From that point on, the user is considered to be authenticated. Let’s look at some code as an example.
從那時起,用戶被認爲是通過身份驗證的。讓咱們以一些代碼爲例。
import org.springframework.security.authentication.*; import org.springframework.security.core.*; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; public class AuthenticationExample { private static AuthenticationManager am = new SampleAuthenticationManager(); public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while(true) { System.out.println("Please enter your username:"); String name = in.readLine(); System.out.println("Please enter your password:"); String password = in.readLine(); try { Authentication request = new UsernamePasswordAuthenticationToken(name, password); Authentication result = am.authenticate(request); SecurityContextHolder.getContext().setAuthentication(result); break; } catch(AuthenticationException e) { System.out.println("Authentication failed: " + e.getMessage()); } } System.out.println("Successfully authenticated. Security context contains: " + SecurityContextHolder.getContext().getAuthentication()); } } class SampleAuthenticationManager implements AuthenticationManager { static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>(); static { AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER")); } public Authentication authenticate(Authentication auth) throws AuthenticationException { if (auth.getName().equals(auth.getCredentials())) { return new UsernamePasswordAuthenticationToken(auth.getName(), auth.getCredentials(), AUTHORITIES); } throw new BadCredentialsException("Bad Credentials"); } }
Here we have written a little program that asks the user to enter a username and password and performs the above sequence. The AuthenticationManager which we’ve implemented here will authenticate any user whose username and password are the same. It assigns a single role to every user. The output from the above will be something like:
在這裏,咱們編寫了一個小程序,要求用戶輸入用戶名和密碼並執行上面的順序。咱們在這裏實現的AuthenticationManager將對用戶名和密碼相同的任何用戶進行身份驗證。它爲每一個用戶分配一個角色。上面的輸出將相似於:
Please enter your username: bob Please enter your password: password Authentication failed: Bad Credentials Please enter your username: bob Please enter your password: bob Successfully authenticated. Security context contains: \ org.springframework.security.authentication.UsernamePasswordAuthenticationToken@441d0230: \ Principal: bob; Password: [PROTECTED]; \ Authenticated: true; Details: null; \ Granted Authorities: ROLE_USER
Note that you don’t normally need to write any code like this. The process will normally occur internally, in a web authentication filter for example. We’ve just included the code here to show that the question of what actually constitutes authentication in Spring Security has quite a simple answer. A user is authenticated when the SecurityContextHolder
contains a fully populated Authentication
object.
請注意,一般不須要編寫這樣的代碼。這個過程一般發生在內部,例如在web身份驗證過濾器中。咱們剛剛在這裏包含了一些代碼,以說明在Spring Security中真正構成身份驗證的問題有一個很是簡單的答案。當SecurityContextHolder
包含一個徹底填充的身份驗證對象時,對用戶進行身份驗證。
In fact, Spring Security doesn’t mind how you put the Authentication
object inside the SecurityContextHolder
. The only critical requirement is that the SecurityContextHolder
contains an Authentication
which represents a principal before the AbstractSecurityInterceptor
(which we’ll see more about later) needs to authorize a user operation.
You can (and many users do) write their own filters or MVC controllers to provide interoperability with authentication systems that are not based on Spring Security. For example, you might be using Container-Managed Authentication which makes the current user available from a ThreadLocal or JNDI location. Or you might work for a company that has a legacy proprietary authentication system, which is a corporate "standard" over which you have little control. In situations like this it’s quite easy to get Spring Security to work, and still provide authorization capabilities. All you need to do is write a filter (or equivalent) that reads the third-party user information from a location, build a Spring Security-specific Authentication
object, and put it into the SecurityContextHolder
. In this case you also need to think about things which are normally taken care of automatically by the built-in authentication infrastructure. For example, you might need to pre-emptively create an HTTP session to cache the context between requests, before you write the response to the client footnote:[It isn’t possible to create a session once the response has been committed.
實際上,Spring Security並不介意您如何將身份驗證對象放入SecurityContextHolder
中。唯一的關鍵需求是,SecurityContextHolder
包含一個身份驗證,在AbstractSecurityInterceptor(稍後將詳細介紹)須要受權用戶操做以前,該身份驗證表明一個主體。
您能夠(許多用戶也能夠)編寫本身的過濾器或MVC控制器,以提供與不基於Spring安全性的身份驗證系統的互操做性。例如,您可能正在使用容器管理的身份驗證,這使得當前用戶能夠從ThreadLocal或JNDI位置訪問。或者,您可能爲一家擁有遺留專有身份驗證系統的公司工做,該系統是一個您幾乎沒法控制的公司「標準」。在這種狀況下,很容易讓Spring Security工做,而且仍然提供受權功能。您所須要作的就是編寫一個過濾器(或等效的過濾器),從一個位置讀取第三方用戶信息,構建一個Spring特定於安全的身份驗證對象,並將其放入SecurityContextHolder
中。在這種狀況下,您還須要考慮一般由內置身份驗證基礎設施自動處理的事情。例如,您可能須要先建立一個HTTP會話,以便在請求之間緩存上下文,而後再編寫對客戶機腳註的響應:[不可能在提交響應以後建立會話。
If you’re wondering how the AuthenticationManager
is implemented in a real world example, we’ll look at that in the core services chapter.
若是您想知道AuthenticationManager
在實際示例中是如何實現的,咱們將在覈心服務一章中對此進行介紹。