Spring3 Web Security机制

spring3.0.x中,加入了基于角色和url删选的Web Security控制。


1. 首先在在web.xml中加入spring security filter:

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

实际上是用这个代理filter里封装了spring一系列security 相关的filter chain。依照处理顺序分别为:

1. org.springframework.security.web.context.SecurityContextPersistenceFilter 查找request的256字符的authority token,找到对应的用户名。

2. org.springframework.security.web.authentication.logout.LogoutFilter 如果为logout操作,清空授权token后往下filfter。

3. org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter username和密码方式验证处理,会讲前端form中传来的username和password进行处理,重名成j_username, j_password后继续往下filter.

4. org.springframework.security.openid.OpenIDAuthenticationFilter spring也支持openID方式的登录,这里会使用openID provider server进行验证。

5. org.springframework.security.web.authentication.www.BasicAuthenticationFilter

6. org.springframework.security.web.savedrequest.RequestCacheAwareFilter

7. org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter 

8. org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter 会记录授权记过到cookie中,在客户端cookie中登录状态缓存。

9. org.springframework.security.web.authentication.AnonymousAuthenticationFilter 检查匿名用户,即request中没有j_userName的情况,会生成默认的匿名用户名称,只对permitAll的表达式通过。

10. org.springframework.security.web.session.SessionManagementFilter 在session中记录或者清除授权结果。

11. org.springframework.security.web.access.ExceptionTranslationFilter 对filter12中授权失败产生的异常进行处理。

12. org.springframework.security.web.access.intercept.FilterSecurityInterceptor 从下面的security url配置中找到access 表达式属性,调用合适的expressionHandler验证权限。


根据url的不同LogoutFilter, UsernamePassAuthenticationFilter, OpenIDAuthencationFilter会选择跳过自己的filter, 调用filter chain往下执行。

直到SecurityContextHolderAwareRequestFilter中,它将原始的request wrap为SecurityContextHolderAwareRequestWrapper类型。这个类型中关键方法有boolean isUserInRole(roleId),再次request wrapper中,spring会从Authentication auth = SecurityContextHolder.getContext().getAuthentication();获取系统当前的已授权的信息。所以,我们通过SecurityContextHolder静态方法,就可以查找到当前req线程权限授权(getContext()会返回req thead上下文的权限状态)。


2. 然后在spring 配置文件中加入security的配置,例如:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied.  See the License for the
  specific language governing permissions and limitations
  under the License.
  -->

<!--
	This security file uses the default spring simple form login
-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       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.0.xsd">

    <security:http auto-config="true" use-expressions="true" disable-url-rewriting="true">
        <security:intercept-url pattern="/newaccount.jsp*" access="permitAll"/>
        <security:intercept-url pattern="/app/newaccount*" access="permitAll"/>
        <security:intercept-url pattern="/login.jsp*" filters="none"/>
        <security:intercept-url pattern="/css/**" access="permitAll"/>
        <security:intercept-url pattern="/images/**" access="permitAll"/>
        <security:intercept-url pattern="/script/**" access="permitAll"/>
        <security:intercept-url pattern="/app/admin/**" access="hasRole('ROLE_ADMIN')"/>
        <!-- all urls must be authenticated -->
        <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
        <security:openid-login user-service-ref="userService" authentication-failure-url="/login.jsp?authfail=openid">
            <security:attribute-exchange>
                <!-- Supported by MyOpenID.com -->
                <security:openid-attribute name="firstName" type="http://schema.openid.net/namePerson/first"/>
                <security:openid-attribute name="lastName" type="http://schema.openid.net/namePerson/last"/>
                <security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true"/>
            </security:attribute-exchange>
        </security:openid-login>
        <security:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?authfail=form"/>
        <security:logout/>
        <security:remember-me/>
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider
                user-service-ref="userService">
            <security:password-encoder ref="passwordEncoder">
                <security:salt-source ref="saltSource"/>
            </security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>
    
    <!-- enable the spring security annotations -->
    <security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled">
        <security:expression-handler ref="expressionHandler"/>
    </security:global-method-security>
    
    <!-- override the default permissionEvaluator bean used by Spring Security with our custom RavePermissionEvaluator -->
    <bean id="expressionHandler" class="org.apache.rave.portal.security.impl.RaveMethodSecurityExpressionHandler">
        <property name="permissionEvaluator" ref="ravePermissionEvaluator" />            
    </bean>
</beans>

在<security:http> use-expressions属性为true时,aceess属性判断role,必须使用hasAnyRole或者hasRole的形式,或者permitAll,不用限制权限。

spring的授权框架会从你提供的userService bean中加载user,这个类必须实现org.springframework.security.core.userdetails.UserDetailsService类,在loadUserByUsername(name)方法中,从我们自己的user库里找到该名字的用户,然后封装成spring的UserDetails类型返回,如果没有就抛UserNotFoundException。在UserDetails中,我们告诉这个找到的user密码、具有的roles(封装在spring GrantedAuthority类型中,其getAuthority()直接返回role id,就是security:http标签中定义的role字符串,比如'ROLE_ADMIN')。


expressionHandlder bean中,spring提供了默认的表达式解析处理类org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler。这个类会对spring默认的权限判断表达式,比如hasAnyRole('role1','role2')进行处理。如果我们要处理自己定制的表达式,集成个类后重写即可。比如此处,我们用自己的permissionEvaluator,对spring传给我们的不同目标资源进行分别处理。


3. 如上文所述,做自己的userService bean,继承自org.springframework.security.core.userdetails.UserDetailsService


 

4. 若果要定制自己的登录界面,<security:form-login>标签中自己制定jsp页面path。表单片段为:

<form id="loginForm" name="loginForm" action="j_spring_security_check" method="post">
        <c:if test="${param['authfail'] eq 'form'}">
            <p class="error"><fmt:message key="page.login.usernamepassword.fail"/></p>
        </c:if>
        <fieldset>
            <p>
                <label for="usernameField"><fmt:message key="page.general.username"/></label>
                <input id="usernameField" type="text" name="j_username" autofocus="autofocus"/>
            </p>

            <p>
                <label for="passwordField"><fmt:message key="page.general.password"/></label>
                <input id="passwordField" type="password" name="j_password"/>
            </p>
            <p>
                <label for="remember_me" class="checkboxLabel">
                    <input type='checkbox' name='_spring_security_remember_me' id="remember_me"
                           value="true"/>
                    <fmt:message key="page.login.rememberme"/>
                </label>
            </p>
        </fieldset>
        <fieldset>
          <fmt:message key="page.login.usernamepassword.login" var="loginButtonText"/>
            <input type="submit" value="${loginButtonText}"/>
        </fieldset>
    </form>

page.login.usernamepassword.faild等为登录失败后要显示的Spring 属性字符串。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值