[转]spring security的原理及教程

Authentication:认证

   

spring security使用分类:

如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1、不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo;2、使用 数据库,根据spring security默认实现代码设计数据库,也就是说数据库已经固定了,这种方法不灵活,而且那个数据库设计得很简陋,实用性差;3、spring security和Acegi不同,它不能修改默认filter了,但支持插入filter,所以根据这个,我们可以插入自己的filter来灵活使 用;4、暴力手段,修改源码,前面说的修改默认filter只是修改配置文件以替换filter而已,这种是直接改了里面的源码,但是这种不符合OO设计 原则,而且不实际,不可用。

本文面向读者:

因为本文准备介绍第三种方法,所以面向的读者是已经具备了spring security基础知识的。不过不要紧,读者可以先看一下这个教程,看完应该可以使用第二种方法开发了。

spring security的简单原理:

使用众多的拦截器对url拦截,以此来管理权限。但是这么多拦截器,笔者不可能对其一一来讲,主要讲里面核心流程的两个。

首先(认证),权限管理离不开登录验证的,所以登录验证拦截器AuthenticationProcessingFilter要讲; 还有就是对访问的资源管理吧,所以资源管理拦截器AbstractSecurityInterceptor要讲; 但拦截器里面的实现需要一些组件来实现,所以就有了AuthenticationManager、accessDecisionManager等组件来支撑。

现在先大概过一遍整个流程,用户登录,会被AuthenticationProcessingFilter拦截,调用 AuthenticationManager的实现,而且AuthenticationManager会调用ProviderManager来获取用户验 证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等),如果验证通过后 会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。

访问资源(即授权管理),访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用 FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,再调用授权管理器 AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信 息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限 不够则报错并调用权限不足页面。 虽然讲得好像好复杂,读者们可能有点晕,不过不打紧,真正通过代码的讲解在后面,读者可以看完后面的代码实现,再返回看这个简单的原理,可能会有不错的收 获。

spring security使用实现(基于spring security3.1.4):

javaEE的入口:web.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

<!--?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:

?


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:

?


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);

        resourceMap.put("/http://blog.csdn.net/u012367513/article/details/other.jsp", attsno);  

        

    

    //参数是要访问的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类的实现:

?


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 name="‘j_username‘" type="‘text‘"></td>

        </tr>

        <tr>

            <td>密码:</td>

            <td><input name="‘j_password‘" type="‘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"%> 

<%@taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> 

 

 

 

<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"%>

<title>My JSP http://blog.csdn.net/u012367513/article/details/admin.jsp starting page</title>

    欢迎来到管理员页面.

    <br>

accessDenied.jsp:

?


1

2

3

4

5

6

7

8

9

<%@page language="java" import="java.util.*" pageEncoding="utf-8"%>

<title>My JSP http://blog.csdn.net/u012367513/article/details/admin.jsp starting page</title>

    欢迎来到管理员页面.

    <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%>">

    

    <title>My JSP http://blog.csdn.net/u012367513/article/details/other.jsp starting page</title>

    

    <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>

 

项目图:
源码和jar包都在这个教程里面,为什么不直接给?笔者的目的是让读者跟着教程敲一遍代码,使印象深刻(相信做这行的都知道,同样一段代码,看过和敲过的区别是多么的大),所以不惜如此来强迫大家了。 由于笔者有经常上csdn博客的习惯,所以读者有什么不懂的(或者指教的),笔者尽力解答。 
转载请标注本文链接:http://blog.csdn.net/u012367513/article/details/38866465

时间: 2024-08-26 14:34:25

[转]spring security的原理及教程的相关文章

Spring Security 入门原理及实战

参考博客: https://www.cnblogs.com/demingblog/p/10874753.html Spring Security 是spring项目之中的一个安全模块,可以非常方便与spring项目无缝集成. 特别是在spring boot项目中加入spring security更是十分简单, 这里就简单介绍一下入门案例和使用原理吧! 写一个简单的springboot测试例子: @Controller public class AppController { @RequestMa

Spring Security安全框架入门篇

一.Spring Security相关概念 1.1..Spring Security介绍: Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全訪问控制解决方式的安全框架(简单说是对訪问权限进行控制嘛).它提供了一组能够在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能.为应用系统提供声明式的安

Spring Security 4 整合Hibernate 实现持久化登录验证(带源码)

上一篇文章:Spring Security 4 整合Hibernate Bcrypt密码加密(带源码) 原文地址:http://websystique.com/spring-security/spring-security-4-remember-me-example-with-hibernate/ [相关已翻译的本系列其他文章,点击分类里面的spring security 4] 本教程将使用Spring Security 4 和hibernate向你展示持久化登录验证. 在持久化登录验证中,应用

Spring Security 3.x 完整入门教程

Spring Security 3.x 出来一段时间了,跟Acegi是大不同了,与2.x的版本也有一些小小的区别,网上有一些文档,也有人翻译Spring Security 3.x的guide,但通过阅读guide,无法马上就能很容易的实现一个完整的实例. 我花了点儿时间,根据以前的实战经验,整理了一份完整的入门教程,供需要的朋友们参考. 1,建一个web project,并导入所有需要的lib,这步就不多讲了. 2,配置web.xml,使用Spring的机制装载: <?xml version=&qu

Spring Security教程系列(一)基础篇

第 1 章 一个简单的HelloWorld 第 1 章 一个简单的HelloWorld Spring Security中可以使用Acegi-1.x时代的普通配置方式,也可以使用从2.0时代才出现的命名空间配置方式,实际上这两者实现的功能是完全一致的,只是新的命名空间配置方式可以把原来需要几百行的配置压缩成短短的几十行.我们的教程中都会使用命名空间的方式进行配置,凡事务求最简. 1.1. 配置过滤器 为了在项目中使用Spring Security控制权限,首先要在web.xml中配置过滤器,这样我

Spring Security教程系列(一)基础篇-2

第 4 章 自定义登陆页面 Spring Security虽然默认提供了一个登陆页面,但是这个页面实在太简陋了,只有在快速演示时才有可能它做系统的登陆页面,实际开发时无论是从美观还是实用性角度考虑,我们都必须实现自定义的登录页面. 4.1. 实现自定义登陆页面 自己实现一个login.jsp,放在src/main/webapp/目录下. 4.2. 修改配置文件 在xml中的http标签中添加一个form-login标签. <http auto-config="true">

Spring Security教程(三):自定义表结构

在上一篇博客中讲解了用Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就算默认提供的表结构很复杂,也不一定能满足项目对用户信息和权限信息管理的要求.那么接下来就讲解如何自定义数据库实现对用户信息和权限信息的管理. 一.自定义表结构 这里还是用的mysql数据库,所以pom.xml文件都不用修改.这里只要新建三张表即可,user表.role表.user_role表.其中user用户表,role角色表为保存用户权限

Spring Security教程(八):用户认证流程源码详解

本篇文章主要围绕下面几个问题来深入源码: 用户认证流程 认证结果如何在多个请求之间共享 获取认证用户信息 一.用户认证流程 上节中提到Spring Security核心就是一系列的过滤器链,当一个请求来的时候,首先要通过过滤器链的校验,校验通过之后才会访问用户各种信息. 这里要说明的是在过滤器的最前端有一个SecurityContextPersistenceFilter,当请求进来和返回的时候都会经过这个过滤器,它主要存放用户的认证信息.这里先简单提一下,后面会详解. 当用户发送登录请求的时候(

spring security使用和原理简析(1)

主要参考:https://blog.csdn.net/u012373815/article/details/55225079 源码参考:https://github.com/527515025/springBoot 项目需求 1:实现了用户.角色.权限的动态管理,可以管控到接口地址,已经访问方式(get,post) 2:自定义登录接口 3:结合spring-session,来保存用户登录信息 表结构说明 method来控制相同方法名的不同访问方式(get,post,put等) 项目结构 废话不多