如何使用spring security,相信百度過的都知道,總共有四種用法,從簡到深爲:一、不用數據庫,所有數據寫在配置文件,這個也是官方文檔裏面的demo;二、使用數據庫,根據spring security默認實現代碼設計數據庫,也就是說數據庫已經固定了,這種方法不靈活,並且那個數據庫設計得很簡陋,實用性差;三、spring security和Acegi不一樣,它不能修改默認filter了,但支持插入filter,因此根據這個,咱們能夠插入本身的filter來靈活使用;四、暴力手段,修改源碼,前面說的修改默認filter只是修改配置文件以替換filter而已,這種是直接改了裏面的源碼,可是這種不符合OO設計原則,並且不實際,不可用。css
由於本文準備介紹第三種方法,因此面向的讀者是已經具有了spring security基礎知識的。不過沒關係,讀者能夠先看一下這個教程,看完應該可使用第二種方法開發了。html
使用衆多的攔截器對url攔截,以此來管理權限。可是這麼多攔截器,筆者不可能對其一一來說,主要講裏面核心流程的兩個。 首先,權限管理離不開登錄驗證的,因此登錄驗證攔截器AuthenticationProcessingFilter要講; 還有就是對訪問的資源管理吧,因此資源管理攔截器AbstractSecurityInterceptor要講; 但攔截器裏面的實現須要一些組件來實現,因此就有了AuthenticationManager、accessDecisionManager等組件來支撐。 如今先大概過一遍整個流程,用戶登錄,會被AuthenticationProcessingFilter攔截,調用AuthenticationManager的實現,並且AuthenticationManager會調用ProviderManager來獲取用戶驗證信息(不一樣的Provider調用的服務不一樣,由於這些信息能夠是在數據庫上,能夠是在LDAP服務器上,能夠是xml配置文件上等),若是驗證經過後會將用戶的權限信息封裝一個User放到spring的全局緩存SecurityContextHolder中,以備後面訪問資源時使用。 訪問資源(即受權管理),訪問url時,會經過AbstractSecurityInterceptor攔截器攔截,其中會調用FilterInvocationSecurityMetadataSource的方法來獲取被攔截url所需的所有權限,在調用受權管理器AccessDecisionManager,這個受權管理器會經過spring的全局緩存SecurityContextHolder獲取用戶的權限信息,還會獲取被攔截的url和被攔截url所需的所有權限,而後根據所配的策略(有:一票決定,一票否認,少數服從多數等),若是權限足夠,則返回,權限不夠則報錯並調用權限不足頁面。 雖然講得好像好複雜,讀者們可能有點暈,不過不打緊,真正經過代碼的講解在後面,讀者能夠看完後面的代碼實現,再返回看這個簡單的原理,可能會有不錯的收穫。 java
javaEE的入口:web.xml:web
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<!--?xml version=
"1.0"
encoding=
"UTF-8"
?-->
<web-app version=
"2.5"
xmlns=
"http://java.sun.com/xml/ns/javaee"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemalocation=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
>
<!--加載Spring XML配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value> classpath:securityConfig.xml </param-value>
</context-param>
<!-- Spring Secutiry3.
1
的過濾器鏈配置 -->
<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>
<!-- Spring 容器啓動監聽器 -->
<listener>
<listener-
class
>org.springframework.web.context.ContextLoaderListener</listener-
class
>
</listener>
<!--系統歡迎頁面 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
|
上面那個配置不用多說了吧 直接上spring security的配置文件securityConfig.xml:正則表達式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<!--?xml version=
"1.0"
encoding=
"UTF-8"
?-->
<b:beans xmlns=
"http://www.springframework.org/schema/security"
xmlns:b=
"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-
3.0
.xsd
http:
//www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!--登陸頁面不過濾 -->
<http pattern=
"/login.jsp"
security=
"none"
>
<http access-denied-page=
"/accessDenied.jsp"
>
<form-login login-page=
"/login.jsp"
>
<!--訪問/http:
//blog.csdn.net/u012367513/article/details/admin.jsp資源的用戶必須具備ROLE_ADMIN的權限 -->
<!-- <intercept-url pattern=
"/http://blog.csdn.net/u012367513/article/details/admin.jsp"
access=
"ROLE_ADMIN"
/> -->
<!--訪問/**資源的用戶必須具備ROLE_USER的權限 -->
<!-- <intercept-url pattern=
"/**"
access=
"ROLE_USER"
/> -->
<session-management>
<concurrency-control max-sessions=
"1"
error-
if
-maximum-exceeded=
"false"
>
</concurrency-control></session-management>
<!--增長一個filter,這點與 Acegi是不同的,不能修改默認的filter了, 這個filter位於FILTER_SECURITY_INTERCEPTOR以前 -->
<custom-filter ref=
"myFilter"
before=
"FILTER_SECURITY_INTERCEPTOR"
>
</custom-filter></form-login></http>
<!--一個自定義的filter,必須包含 authenticationManager,accessDecisionManager,securityMetadataSource三個屬性,
咱們的全部控制將在這三個類中實現,解釋詳見具體配置 -->
<b:bean id=
"myFilter"
class
=
"com.erdangjiade.spring.security.MyFilterSecurityInterceptor"
>
<b:property name=
"authenticationManager"
ref=
"authenticationManager"
>
<b:property name=
"accessDecisionManager"
ref=
"myAccessDecisionManagerBean"
>
<b:property name=
"securityMetadataSource"
ref=
"securityMetadataSource"
>
</b:property></b:property></b:property></b:bean>
<!--驗證配置,認證管理器,實現用戶認證的入口,主要實現UserDetailsService接口便可 -->
<!--若是用戶的密碼採用加密的話 <password-encoder hash=
"md5"
/> -->
</authentication-provider>
</authentication-manager>
<!--在這個類中,你就能夠從數據庫中讀入用戶的密碼,角色信息,是否鎖定,帳號是否過時等 -->
<b:bean id=
"myUserDetailService"
class
=
"com.erdangjiade.spring.security.MyUserDetailService"
>
<!--訪問決策器,決定某個用戶具備的角色,是否有足夠的權限去訪問某個資源 -->
<b:bean id=
"myAccessDecisionManagerBean"
class
=
"com.erdangjiade.spring.security.MyAccessDecisionManager"
>
</b:bean>
<!--資源源數據定義,將全部的資源和權限對應關係創建起來,即定義某一資源能夠被哪些角色訪問 -->
<b:bean id=
"securityMetadataSource"
class
=
"com.erdangjiade.spring.security.MyInvocationSecurityMetadataSource"
>
</b:bean></b:bean></http></b:beans>
|
其實全部配置都在裏面,首先這個版本的spring security不支持了filter=none的配置了,改爲了獨立的,裏面你能夠配登錄頁面、權限不足的返回頁面、註銷頁面等,上面那些配置,我註銷了一些資源和權限的對應關係,筆者這裏不須要在這配死它,能夠本身寫攔截器來得到資源與權限的對應關係。 session-management是用來防止多個用戶同時登錄一個帳號的。
最重要的是筆者本身寫的攔截器myFilter(終於講到重點了),首先這個攔截器會加載在FILTER_SECURITY_INTERCEPTOR以前(配置文件上有說),最主要的是這個攔截器裏面配了三個處理類,第一個是authenticationManager,這個是處理驗證的,這裏須要特別說明的是:這個類不單隻這個攔截器用到,還有驗證攔截器AuthenticationProcessingFilter也用到 了,並且實際上的登錄驗證也是AuthenticationProcessingFilter攔截器調用authenticationManager來處理的,咱們這個攔截器只是爲了拿到驗證用戶信息而已(這裏不太清楚,由於authenticationManager筆者設了斷點,用戶登錄後再也沒調用這個類了,並且調用這個類時不是筆者本身寫的那個攔截器調用的,看了spring技術內幕這本書才知道是AuthenticationProcessingFilter攔截器調用的)。 securityMetadataSource這個用來加載資源與權限的所有對應關係的,並提供一個經過資源獲取全部權限的方法。
accessDecisionManager這個也稱爲受權器,經過登陸用戶的權限信息、資源、獲取資源所需的權限來根據不一樣的受權策略來判斷用戶是否有權限訪問資源。
authenticationManager類能夠有許多provider(提供者)提供用戶驗證信息,這裏筆者本身寫了一個類myUserDetailService來獲取用戶信息。
MyUserDetailService:spring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package
com.erdangjiade.spring.security;
import
java.util.ArrayList;
import
java.util.Collection;
import
org.springframework.dao.DataAccessException;
import
org.springframework.security.core.GrantedAuthority;
import
org.springframework.security.core.authority.GrantedAuthorityImpl;
import
org.springframework.security.core.userdetails.User;
import
org.springframework.security.core.userdetails.UserDetails;
import
org.springframework.security.core.userdetails.UserDetailsService;
import
org.springframework.security.core.userdetails.UsernameNotFoundException;
public
class
MyUserDetailService
implements
UserDetailsService {
//登錄驗證時,經過username獲取用戶的全部權限信息,
//並返回User放到spring的全局緩存SecurityContextHolder中,以供受權器使用
public
UserDetails loadUserByUsername(String username)
throws
UsernameNotFoundException, DataAccessException {
Collection<grantedauthority> auths=
new
ArrayList<grantedauthority>();
GrantedAuthorityImpl auth2=
new
GrantedAuthorityImpl(
"ROLE_ADMIN"
);
GrantedAuthorityImpl auth1=
new
GrantedAuthorityImpl(
"ROLE_USER"
);
if
(username.equals(
"lcy"
)){
auths=
new
ArrayList<grantedauthority>();
auths.add(auth1);
auths.add(auth2);
}
User user =
new
User(username,
"lcy"
,
true
,
true
,
true
,
true
, auths);
return
user;
}
} </grantedauthority></grantedauthority></grantedauthority>
|
其中UserDetailsService接口是spring提供的,必須實現的。別看這個類只有一個方法,並且這麼簡單,其中內涵玄機。 讀者看到這裏可能就大感疑惑了,不是說好的用數據庫嗎?對,但別急,等筆者慢慢給大家解析。 首先,筆者爲何不用數據庫,還不是爲了讀者們測試方便,並簡化spring security的流程,讓讀者抓住主線,而不是還要煩其餘事(導入數據庫,配置數據庫,寫dao等)。 這裏筆者只是用幾個數據模擬了從數據庫中拿到的數據,也就是說ROLE_ADMIN、ROLE_USER、lcy(第一個是登錄帳號)、lcy(第二個是密碼)是從數據庫拿出來的,這個不難實現吧,若是須要數據庫時,讀者能夠用本身寫的dao經過參數username來查詢出這個用戶的權限信息(或是角色信息,就是那個ROLE_*,對必須是ROLE_開頭的,否則spring security不認帳的,實際上是spring security裏面作了一個判斷,必需要ROLE_開頭,讀者能夠百度改一下),再返回spring自帶的數據模型User便可。 這個寫應該比較清晰、靈活吧,總之數據讀者們經過什麼方法獲取都行,只要返回一個User對象就好了。(這也是筆者爲何要重寫這個類的緣由)
經過MyUserDetailService拿到用戶信息後,authenticationManager對比用戶的密碼(即驗證用戶),而後這個AuthenticationProcessingFilter攔截器就過咯。
下面要說的是另一個攔截器,就是筆者本身寫的攔截器MyFilterSecurityInterceptor:sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package
com.erdangjiade.spring.security;
import
java.io.IOException;
import
javax.servlet.Filter;
import
javax.servlet.FilterChain;
import
javax.servlet.FilterConfig;
import
javax.servlet.ServletException;
import
javax.servlet.ServletRequest;
import
javax.servlet.ServletResponse;
import
org.springframework.security.access.SecurityMetadataSource;
import
org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import
org.springframework.security.access.intercept.InterceptorStatusToken;
import
org.springframework.security.web.FilterInvocation;
import
org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
public
class
MyFilterSecurityInterceptor
extends
AbstractSecurityInterceptor
implements
Filter {
//配置文件注入
private
FilterInvocationSecurityMetadataSource securityMetadataSource;
//登錄後,每次訪問資源都經過這個攔截器攔截
public
void
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws
IOException, ServletException {
FilterInvocation fi =
new
FilterInvocation(request, response, chain);
invoke(fi);
}
public
FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return
this
.securityMetadataSource;
}
public
Class<!--?
extends
Object--> getSecureObjectClass() {
return
FilterInvocation.
class
;
}
public
void
invoke(FilterInvocation fi)
throws
IOException, ServletException {
//fi裏面有一個被攔截的url
//裏面調用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法獲取fi對應的全部權限
//再調用MyAccessDecisionManager的decide方法來校驗用戶的權限是否足夠
InterceptorStatusToken token =
super
.beforeInvocation(fi);
try
{
//執行下一個攔截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
finally
{
super
.afterInvocation(token,
null
);
}
}
public
SecurityMetadataSource obtainSecurityMetadataSource() {
return
this
.securityMetadataSource;
}
public
void
setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource newSource)
{
this
.securityMetadataSource = newSource;
}
public
void
destroy() {
}
public
void
init(FilterConfig arg0)
throws
ServletException {
}
}
|
繼承AbstractSecurityInterceptor、實現Filter是必須的。 首先,登錄後,每次訪問資源都會被這個攔截器攔截,會執行doFilter這個方法,這個方法調用了invoke方法,其中fi斷點顯示是一個url(可能重寫了toString方法吧,可是裏面還有一些方法的),最重要的是beforeInvocation這個方法,它首先會調用MyInvocationSecurityMetadataSource類的getAttributes方法獲取被攔截url所需的權限,在調用MyAccessDecisionManager類decide方法判斷用戶是否夠權限。弄完這一切就會執行下一個攔截器。
再看一下這個MyInvocationSecurityMetadataSource的實現:數據庫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package
com.erdangjiade.spring.security;
import
java.util.ArrayList;
import
java.util.Collection;
import
java.util.HashMap;
import
java.util.Iterator;
import
java.util.Map;
import
org.springframework.security.access.ConfigAttribute;
import
org.springframework.security.access.SecurityConfig;
import
org.springframework.security.web.FilterInvocation;
import
org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import
com.erdangjiade.spring.security.tool.AntUrlPathMatcher;
import
com.erdangjiade.spring.security.tool.UrlMatcher;
public
class
MyInvocationSecurityMetadataSource
implements
FilterInvocationSecurityMetadataSource {
private
UrlMatcher urlMatcher =
new
AntUrlPathMatcher();
private
static
Map<string, collection<configattribute=
""
>> resourceMap =
null
;
//tomcat啓動時實例化一次
public
MyInvocationSecurityMetadataSource() {
loadResourceDefine();
}
//tomcat開啓時加載一次,加載全部url和權限(或角色)的對應關係
private
void
loadResourceDefine() {
resourceMap =
new
HashMap<string, collection<configattribute=
""
>>();
Collection<configattribute> atts =
new
ArrayList<configattribute>();
ConfigAttribute ca =
new
SecurityConfig(
"ROLE_USER"
);
atts.add(ca);
resourceMap.put(
"/index.jsp"
, atts);
Collection<configattribute> attsno =
new
ArrayList<configattribute>();
ConfigAttribute cano =
new
SecurityConfig(
"ROLE_NO"
);
attsno.add(cano);
}
//參數是要訪問的url,返回這個url對於的全部權限(或角色)
public
Collection<configattribute> getAttributes(Object object)
throws
IllegalArgumentException {
// 將參數轉爲url
String url = ((FilterInvocation)object).getRequestUrl();
Iterator<string>ite = resourceMap.keySet().iterator();
while
(ite.hasNext()) {
String resURL = ite.next();
if
(urlMatcher.pathMatchesUrl(resURL, url)) {
return
resourceMap.get(resURL);
}
}
return
null
;
}
public
boolean
supports(Class<!--?-->clazz) {
return
true
;
}
public
Collection<configattribute> getAllConfigAttributes() {
return
null
;
}
}
</configattribute></string></configattribute></configattribute></configattribute></configattribute></configattribute></string,></string,>
|
實現FilterInvocationSecurityMetadataSource接口也是必須的。 首先,這裏也是模擬了從數據庫中獲取信息。 其中loadResourceDefine方法不是必須的,這個只是加載全部的資源與權限的對應關係並緩存起來,避免每次獲取權限都訪問數據庫(提升性能),而後getAttributes根據參數(被攔截url)返回權限集合。 這種緩存的實現其實有一個缺點,由於loadResourceDefine方法是放在構造器上調用的,而這個類的實例化只在web服務器啓動時調用一次,那就是說loadResourceDefine方法只會調用一次,若是資源和權限的對應關係在啓動後發生了改變,那麼緩存起來的就是髒數據,而筆者這裏使用的就是緩存數據,那就會受權錯誤了。但若是資源和權限對應關係是不會改變的,這種方法性能會好不少。 如今說回有數據庫的靈活實現,讀者看到這,可能會說,這還不簡單,和上面MyUserDetailService類同樣使用dao靈活獲取數據就行啦。 若是讀者這樣想,那隻想到了一半,想一下spring的機制(依賴注入),dao須要依賴注入吧,但這是在啓動時候,那個dao可能都還沒加載,因此這裏須要讀者本身寫sessionFactory,本身寫hql或sql,對,就在loadResourceDefine方法裏面寫(這個應該會寫吧,基礎來的)。那若是說想用第二種方法呢(就是容許資源和權限的對應關係改變的那個),那更加簡單,根本不須要loadResourceDefine方法了,直接在getAttributes方法裏面調用dao(這個是加載完,後來纔會調用的,因此可使用dao),經過被攔截url獲取數據庫中的全部權限,封裝成Collection返回就好了。(靈活、簡單) 注意:接口UrlMatcher和實現類AntUrlPathMatcher是筆者本身寫的,這原本是spring之前版本有的,如今沒有了,可是以爲好用就用會來了,直接上代碼(讀者也能夠本身寫正則表達式驗證被攔截url和緩存或數據庫的url是否匹配):緩存
1
2
3
4
5
6
7
8
|
package
com.erdangjiade.spring.security.tool;
public
interface
UrlMatcher{
Object compile(String paramString);
boolean
pathMatchesUrl(Object paramObject, String paramString);
String getUniversalMatchPattern();
boolean
requiresLowerCaseUrl();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
package
com.erdangjiade.spring.security.tool;
import
org.springframework.util.AntPathMatcher;
import
org.springframework.util.PathMatcher;
public
class
AntUrlPathMatcher
implements
UrlMatcher {
private
boolean
requiresLowerCaseUrl;
private
PathMatcher pathMatcher;
public
AntUrlPathMatcher() {
this
(
true
);
}
public
AntUrlPathMatcher(
boolean
requiresLowerCaseUrl)
{
this
.requiresLowerCaseUrl =
true
;
this
.pathMatcher =
new
AntPathMatcher();
this
.requiresLowerCaseUrl = requiresLowerCaseUrl;
}
public
Object compile(String path) {
if
(
this
.requiresLowerCaseUrl) {
return
path.toLowerCase();
}
return
path;
}
public
void
setRequiresLowerCaseUrl(
boolean
requiresLowerCaseUrl){
this
.requiresLowerCaseUrl = requiresLowerCaseUrl;
}
public
boolean
pathMatchesUrl(Object path, String url) {
if
((
"/**"
.equals(path)) || (
"**"
.equals(path))) {
return
true
;
}
return
this
.pathMatcher.match((String)path, url);
}
public
String getUniversalMatchPattern() {
return
"/**"
;
}
public
boolean
requiresLowerCaseUrl() {
return
this
.requiresLowerCaseUrl;
}
public
String toString() {
return
super
.getClass().getName() +
"[requiresLowerCase='"
+
this
.requiresLowerCaseUrl +
"']"
;
}
}
|
而後MyAccessDecisionManager類的實現:tomcat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package
com.erdangjiade.spring.security;
import
java.util.Collection;
import
java.util.Iterator;
import
org.springframework.security.access.AccessDecisionManager;
import
org.springframework.security.access.AccessDeniedException;
import
org.springframework.security.access.ConfigAttribute;
import
org.springframework.security.access.SecurityConfig;
import
org.springframework.security.authentication.InsufficientAuthenticationException;
import
org.springframework.security.core.Authentication;
import
org.springframework.security.core.GrantedAuthority;
public
class
MyAccessDecisionManager
implements
AccessDecisionManager {
//檢查用戶是否夠權限訪問資源
//參數authentication是從spring的全局緩存SecurityContextHolder中拿到的,裏面是用戶的權限信息
//參數object是url
//參數configAttributes所需的權限
public
void
decide(Authentication authentication, Object object,
Collection<configattribute> configAttributes)
throws
AccessDeniedException, InsufficientAuthenticationException {
if
(configAttributes ==
null
){
return
;
}
Iterator<configattribute> ite=configAttributes.iterator();
while
(ite.hasNext()){
ConfigAttribute ca=ite.next();
String needRole=((SecurityConfig)ca).getAttribute();
for
(GrantedAuthority ga : authentication.getAuthorities()){
if
(needRole.equals(ga.getAuthority())){
return
;
}
}
}
//注意:執行這裏,後臺是會拋異常的,可是界面會跳轉到所配的access-denied-page頁面
throw
new
AccessDeniedException(
"no right"
);
}
public
boolean
supports(ConfigAttribute attribute) {
return
true
;
}
public
boolean
supports(Class<!--?-->clazz) {
return
true
;
}
}</configattribute></configattribute>
|
接口AccessDecisionManager也是必須實現的。 decide方法裏面寫的就是受權策略了,筆者的實現是,沒有明說須要權限的(即沒有對應的權限的資源),能夠訪問,用戶具備其中一個或多個以上的權限的能夠訪問。這個就看需求了,須要什麼策略,讀者能夠本身寫其中的策略邏輯。經過就返回,不經過拋異常就好了,spring security會自動跳到權限不足頁面(配置文件上配的)。
就這樣,整個流程過了一遍。
原本想給這個demo的源碼出來的,可是筆者以爲,經過這個教程一步一步讀下來,並本身敲一遍代碼,會比直接運行一遍demo印象更深入,而且更容易理解裏面的原理。 並且個人源碼其實都公佈出來了: login.jsp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<%
@page
language=
"java"
import
=
"java.util.*"
pageEncoding=
"UTF-8"
%>
<title>登陸</title>
<form action=
"j_spring_security_check"
method=
"POST"
>
<table>
<tbody><tr>
<td>用戶:</td>
<td><input type=
"'text'"
name=
"'j_username'"
></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type=
"'password'"
name=
"'j_password'"
></td>
</tr>
<tr>
<td><input name=
"reset"
type=
"reset"
></td>
<td><input name=
"submit"
type=
"submit"
></td>
</tr>
</tbody></table>
</form>
|
index.jsp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<%
@page
language=
"java"
import
=
"java.util.*"
pageEncoding=
"UTF-8"
%>
<title>My JSP
'index.jsp'
starting page</title>
<h3>這是首頁</h3>歡迎
<sec:authentication property=
"name"
> !
<br>
進入admin頁面
進入其它頁面
</sec:authentication>
|
http://blog.csdn.net/u012367513/article/details/admin.jsp:
1
2
3
4
5
6
7
8
9
|
<%
@page
language=
"java"
import
=
"java.util.*"
pageEncoding=
"utf-8"
%>
歡迎來到管理員頁面.
<br>
|
accessDenied.jsp:
1
2
3
4
5
6
7
8
9
|
<%
@page
language=
"java"
import
=
"java.util.*"
pageEncoding=
"utf-8"
%>
歡迎來到管理員頁面.
<br>
|
http://blog.csdn.net/u012367513/article/details/other.jsp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<%@ page language=
"java"
import
=
"java.util.*"
pageEncoding=
"UTF-8"
%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+
"://"
+request.getServerName()+
":"
+request.getServerPort()+path+
"/"
;
%>
<base href=
"<%=basePath%>"
>
<meta http-equiv=
"pragma"
content=
"no-cache"
>
<meta http-equiv=
"cache-control"
content=
"no-cache"
>
<meta http-equiv=
"expires"
content=
"0"
>
<meta http-equiv=
"keywords"
content=
"keyword1,keyword2,keyword3"
>
<meta http-equiv=
"description"
content=
"This is my page"
>
<!--
<link rel=
"stylesheet"
type=
"text/css"
href=
"styles.css"
>
-->
<h3>這裏是Other頁面</h3>
|
項目圖:
<img src="http://www.2cto.com/uploadfile/Collfiles/20140829/20140829091240286.png" alt="n峨n竩�漽j喎�" http:="" www.2cto.com="" ym"="" target="_blank" class="keylink" style="border-width: 0px; padding: 0px; margin: 0px; list-style: none; width: 322px; height: 464px;">源碼和jar包都在這個教程裏面,爲何不直接給?筆者的目的是讓讀者跟着教程敲一遍代碼,使印象深入(相信作這行的都知道,一樣一段代碼,看過和敲過的區別是多麼的大),因此不惜如此來強迫你們了。
轉自:http://blog.csdn.net/u013516966/article/details/46688765