spring security3.2 总结

6 篇文章 0 订阅

spring security 总共有11个过滤器,依顺序如下:

'SecurityContextPersistenceFilter'       
'WebAsyncManagerIntegrationFilter'       
'LogoutFilter'                           
'UsernamePasswordAuthenticationFilter'   
'BasicAuthenticationFilter'              
'RequestCacheAwareFilter'                
'SecurityContextHolderAwareRequestFilter'
'AnonymousAuthenticationFilter'          
'SessionManagementFilter'                
 'ExceptionTranslationFilter'                  
 'FilterSecurityInterceptor'             

每个过滤器依次调用。
主要是会用到UsernamePasswordAuthenticationFilter、FilterSecurityInterceptor

bean配置:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:sec="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.2.xsd"

>


    <!-- 密码加密类和解密工具-->  
    <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
    <!-- 密码加密类和解密用的盐-->   
    <bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">  
        <property name="userPropertyToUse" value="username"/>  
    </bean>  
    
    <!-- 定义上下文返回的消息的国际化 -->  
    <bean id="messageSource"  
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
        <property name="basename"  
            value="classpath:messages_zh_CN"/>  
    </bean>
    
    <!-- 启用用户的缓存功能 -->
    <bean id="userCache"  
        class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">  
        <property name="cache" ref="userEhCache" />  
    </bean>  
      
    <bean id="userEhCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">  
        <property name="cacheName" value="userCache" />  
        <property name="cacheManager" ref="cacheManager" />  
    </bean>  
      
    <bean id="cacheManager"  

        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />


    <!-- 根据登录帐号查询用户信息 -->
    <bean id="userDetailsService" class="com.phms.security.SysUserDetailsService" />


<!--  配置 免权限访问资源  -->

    <sec:http pattern="/**/*.css" security="none"/>  
    <sec:http pattern="/**/*.jpg" security="none"/>  
    <sec:http pattern="/**/*.jpeg" security="none"/>  
    <sec:http pattern="/**/*.gif" security="none"/>  
    <sec:http pattern="/**/*.png" security="none"/>  
    <sec:http pattern="/**/*.js" security="none"/>  
    <sec:http pattern="/login.jsp" security="none"/>


<!--  security 配置  -->

<sec:http auto-config="true"  entry-point-ref="authenticationProcessingFilterEntryPoint">
    
        <!--权限不足处理程序 -->
        <sec:access-denied-handler ref="accessDeniedHandler"/>
       

        <!--  配置登录UsernamePasswordAuthenticationFilter的属性

                UsernamePasswordAuthenticationFilter,对用户进行授权,比如进行密码验证。

                它会自动注入bean:userDetailsService、passwordEncoder、userCache、messageSource。

                如果不需要授权成功或失败后进行特殊处理,下面两行:

                authentication-failure-handler-ref="authenticationFailureHandler"
                authentication-success-handler-ref="authenticationSuccessHandler

                可以配置为:

                 authentication-failure-url="/login.jsp?error=true"  
                 default-target-url="/welcome”。


            login-processing-url="/j_spring_security_check"        登入页面form action 这个不配置的话,默认就是action=“/j_spring_security_check”,可以改
            password-parameter="j_password"                              帐号默认name="j_username",可以改
            username-parameter="j_username"                            密码默认name="j_password",可以改
            (没用过spring security 的要注意,网上很多介绍spring security 的,但是不给登入页面,新手刚开始不知道默认是这个,然后又不知道哪里配置,

             登入后始终达不到想要的目的。)

        -->
        <sec:form-login login-page="/login.jsp"
            login-processing-url="/j_spring_security_check"  
            password-parameter="j_password"
            username-parameter="j_username"
            authentication-failure-handler-ref="authenticationFailureHandler"
            authentication-success-handler-ref="authenticationSuccessHandler"/>  
 

        <!--  登出配置  -->
        <sec:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp" />

        <!--  会话超时转到登录页面  -->
        <sec:session-management invalid-session-url="/login.jsp" />            
        
          
        <sec:custom-filter  ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>   
    </sec:http>


    <!-- 登入信息验证成功后,登入系统主页 -->
       <bean id="authenticationSuccessHandler"  
        class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">  
        <property name="defaultTargetUrl" value="/welcome"/>  
    </bean>  
    <!-- 登入信息验证失败后,退回到登入页面 -->
    <bean id="authenticationFailureHandler"  
        class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">  
        <property name="defaultFailureUrl" value="/login.jsp?error=true"/>  
    </bean>


     <!-- 过滤安全拦截器,对用户密码及用户访问资源需要的权限进行验证 -->
    <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <!-- 主要是取得资源和权限的关系映射 -->  
        <property name="securityMetadataSource" ref="securityMetadataSource" />
        <!-- 检查必须配置有资源和权限的关系映射的资源可以进行访问
            比如:a.jsp没有资源和权限的关系映射,如果此时默认为false,那么直接输入http:localhost:8080/project/a.jsp也是可以访问的。
                这样会有隐藏的风险,应该所有资源都配置权限。
         -->
        <property name="rejectPublicInvocations" value="true"/>
        <!-- 1.取得用户信息、用户和权限的关系映射; 2.进行用户密码验证;-->
        <property name="authenticationManager" ref="authenticationManager" />  
        <!-- 如果是true,总是要进行密码验证;如果是False,authenticationManager只会调用一次进行验证,验证成功后,不会再重复调用进行验证。
        <property name="alwaysReauthenticate" ref="false" /> -->
        <!-- 把 资源和权限的关系映射 与 用户和权限的关系映射 进行权限投票 ,投票通过的资源用户可以访问-->
        <property name="accessDecisionManager" ref="accessDecisionManager" />       
    </bean>  

    <!-- 验证授权异常,退回到登入页面  
        authenticationProcessingFilterEntryPoint,accessDeniedHandler什么时候用,可以研究一下ExceptionTranslationFilter。
        从ExceptionTranslationFilter知道,
        1.authenticationProcessingFilterEntryPoint针对AuthenticationException异常时行 处理,此异常只在authentication的时候使用,Authentication成功后,

        不会再进行    Authentication,所以authenticationProcessingFilterEntryPoint,在filterSecurityInterceptor.alwaysReauthenticate默认为false情况下只会在登入时候使用。
        2.accessDeniedHandler在用户不为匿名访问情况下,针对AccessDeniedException异常时行 处理,此异常在accessDecisionManager时候使用,

        在系统运行时对所有资源进行认证。 所以accessDecisionManager只要用户有访问,它就会被调用。
     -->  
    <bean id="authenticationProcessingFilterEntryPoint" class="com.phms.security.SysLoginUrlAuthenticationEntryPoint">  
        <property name="loginFormUrl" value="/login.jsp?error=true"/>
    </bean>      
    <!-- 认证权限不足,退回到登入页面
        authenticationProcessingFilterEntryPoint,accessDeniedHandler什么时候用,可以研究一下ExceptionTranslationFilter。
        从ExceptionTranslationFilter知道,
        1.authenticationProcessingFilterEntryPoint针对AuthenticationException异常时行 处理,此异常只在authentication的时候使用,Authentication成功后,

          不会再进行 Authentication, 所以authenticationProcessingFilterEntryPoint,在filterSecurityInterceptor.alwaysReauthenticate默认为false情况下只会在登入时候使用。
        2.accessDeniedHandler在用户不为匿名访问情况下,针对AccessDeniedException异常时行 处理,此异常在accessDecisionManager时候使用,

       在系统运行时对所有资源进行认证。 所以accessDecisionManager只要用户有访问,它就会被调用。
    -->
    <bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl" >
        <property name="errorPage" value="/login.jsp?error=denied"/>
    </bean>    
    
    <!-- 权限验证,主要是把用户权限与资源权限进行比对,如果有相同权限,就算验证通过,可以对资源进行请求
          验证通过方式,方式有三种:
         一票通过:org.springframework.security.access.vote.AffirmativeBased
         多数通过:org.springframework.security.access.vote.ConsensusBased
         一票否决:org.springframework.security.access.vote.UnanimousBased
    -->
    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">  
        <constructor-arg name="decisionVoters">  
            <list>  
                <ref bean="authenticatedVoter"/>  
                <ref bean="roleVoter"/>  
            </list>  
        </constructor-arg>  
        <property name="messageSource" ref="messageSource"/>  
    </bean>  
    
    <!-- 投票器。配置它主要是根据用户访问权限进行投票。用户访问权限(为了区别我把它们也称为系统权限), 用户访问权限有三个:
        IS_AUTHENTICATED_FULLY(只允许登入用户访问)
        IS_AUTHENTICATED_REMEMBERED(允许登入用户和记名用户访问)
        IS_AUTHENTICATED_ANONYMOUSLY(允许登入用户、记名用户还有匿名用户访问,实际上就是不做访问权限验证)
        投票结果有三个:ACCESS_GRANTED(通过)、ACCESS_ABSTAIN(弃权)、ACCESS_DENIED(否决)
    -->
    <bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" />
    <!-- 投票器。配置它主要是:一、对自定义权限前缀进行控制,二、根据自定义权限进行投票。  
         结果同样有三个:ACCESS_GRANTED(通过)、ACCESS_ABSTAIN(弃权)、ACCESS_DENIED(否决)-->  
    <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">  
        <!-- 权限前缀  此属性不配置的话,默认是"ROLE_",如果不要前缀可以设置为空   -->
        <property name="rolePrefix" value="R_"/>  
    </bean>  
      
    <!-- 1.取得用户信息、用户和权限的关系映射; 2.进行用户密码验证;-->
    <sec:authentication-manager alias="authenticationManager">  
        <sec:authentication-provider ref="authenticationProvider" />      
    </sec:authentication-manager>  

    <!-- 引服务提供给spring security authentication manager 用户认证信息,包括权限、密码、密盐-->
    <bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <!-- 此属性为spring security 内置的属性,开启UserNotFoundException-->  
        <property name="hideUserNotFoundExceptions" value="false" />
        <!-- 取得用户信息、用户和权限的关系映射;-->  
        <property name="userDetailsService" ref="userDetailsService" />  
        <property name="passwordEncoder" ref="passwordEncoder" />  
        <property name="saltSource" ref="saltSource" />  
    </bean> 
    

/**
 * 根据用户名,加载用户的认证信息,包括用户的权限和用户登录信息
 * 提供给spring security authentication manager 进行认证
 * @author swy
 */
public class SysUserDetailsService implements UserDetailsService {

    protected final Logger log = LoggerFactory.getLogger(SysUserDetailsService.class);  
    @Autowired  
    private MessageSource messageSource;  
      
    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        
        //此处可以通过数据库访问取得用户信息


    
        Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();  
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("R_A");
        auths.add(grantedAuthority);

        //UserBO 必须实现UserDetails
        UserDetails user = new UserBO("1","admin","c3ce8345d3599ab8a4c337d9fb0d0d93",true,true,true,true,auths);
          
        if(log.isDebugEnabled()) log.debug(StringUtils.bean2Str(user.getAuthorities()));  
          
        return user;  
    }

    public MessageSource getMessageSource() {
        return messageSource;
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }


    public static void main(String[] args) {
        //生成MD5加密的密码
        MessageDigestPasswordEncoder mp = new MessageDigestPasswordEncoder("MD5");
        System.out.println(mp.encodePassword("1", "admin"));
    }
}




/**
 * 取得资源和权限的关系映射
 * @author swy
 *
 */
@Service("securityMetadataSource")
public class SysFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static final Logger log = LoggerFactory.getLogger(SysFilterInvocationSecurityMetadataSource.class);
     private final static List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = Collections.emptyList();  
        //权限集合  
        private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;  
          
        @Override  
        public Collection<ConfigAttribute> getAttributes(Object object)  
                throws IllegalArgumentException {  
            final HttpServletRequest request = ((FilterInvocation) object).getRequest();  
            System.out.println("URL资源:"+request.getRequestURI()+ " -> ");
              
            for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : this.bindRequestMap().entrySet()) {  
                if (entry.getKey().matches(request)) {  
                    LogUtils.autolog(log,"URL资源:"+request.getRequestURI()+ " -> " + entry.getValue());  
                    return entry.getValue();  
                }  
            }  
            return NULL_CONFIG_ATTRIBUTE;  
        }  

        @Override  
        public Collection<ConfigAttribute> getAllConfigAttributes() {  
            Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();  
      
            for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : this.bindRequestMap().entrySet()) {  
                allAttributes.addAll(entry.getValue());  
            }  
      
            return allAttributes;  
        }  
      

        @Override  
        public boolean supports(Class<?> clazz) {  
            return FilterInvocation.class.isAssignableFrom(clazz);  
        }  
          
        private Map<String,String> loadResuorce(){  
            Map<String,String> map = new LinkedHashMap<String,String>();  
            //此处可以通过数据库访问取得用户信息
            List<Map<String,String>> list = new ArrayList<Map<String,String>>();
            map.put("/welcome", "R_A,IS_AUTHENTICATED_ANONYMOUSLY");
            map.put("/menu/*", "R_A,R_B");
            map.put("/order/*", "R_A,R_B");
            return map;  
        }  
          
        protected Map<RequestMatcher, Collection<ConfigAttribute>> bindRequestMap(){  
            Map<RequestMatcher, Collection<ConfigAttribute>> map =   
                    new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();  
              
            Map<String,String> resMap = this.loadResuorce();  
            for(Map.Entry<String,String> entry:resMap.entrySet()){  
                String key = entry.getKey();  
                Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();  
                atts = SecurityConfig.createListFromCommaDelimitedString(entry.getValue());  
                map.put(new AntPathRequestMatcher(key), atts);  
            }  
              
            return map;  
        }  
      
        @PostConstruct
        public void afterPropertiesSet() throws Exception{  
            this.requestMap = this.bindRequestMap();  
        }  
          
        public void refreshResuorceMap(){  
            this.requestMap = this.bindRequestMap();  
        }  
}



/**
        验证授权异常,退回到登入页面  
        authenticationProcessingFilterEntryPoint,accessDeniedHandler什么时候用,可以研究一下ExceptionTranslationFilter。
        从ExceptionTranslationFilter知道,
        1.authenticationProcessingFilterEntryPoint针对AuthenticationException异常时行 处理,此异常只在authentication的时候使用,Authentication成功后,不会再进行 Authentication,
        所以authenticationProcessingFilterEntryPoint,在filterSecurityInterceptor.alwaysReauthenticate默认为false情况下只会在登入时候使用。
        2.accessDeniedHandler在用户不为匿名访问情况下,针对AccessDeniedException异常时行 处理,此异常在accessDecisionManager时候使用,在系统运行时对所有资源进行认证。
        所以accessDecisionManager只要用户有访问,它就会被调用。
 * @author swy
 *
 */
@SuppressWarnings("deprecation")
public class SysLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
    private static final Log logger = LogFactory.getLog(SysLoginUrlAuthenticationEntryPoint.class);    

    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
   
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
            throws IOException, ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("SysLoginUrlAuthenticationEntryPoint: " + getLoginFormUrl());
        }

        String redirectUrl = null;
        if (isUseForward()) {

            if (isForceHttps() && "http".equals(request.getScheme())) {
                // First redirect the current request to HTTPS.
                // When that request is received, the forward to the login page will be used.
                redirectUrl = buildHttpsRedirectUrlForRequest(request);
            }

            if (redirectUrl == null) {
                String loginForm = determineUrlToUseForThisRequest(request, response, authException);

                if (logger.isDebugEnabled()) {
                    logger.debug("Server side forward to: " + loginForm);
                }
                // 传递异常到页面
                request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, authException);
                
                RequestDispatcher dispatcher = request.getRequestDispatcher(loginForm);

                dispatcher.forward(request, response);

                return;
            }
        } else {
            // redirect to login page. Use https if forceHttps true

            redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
            
            //传递异常到页面
            request.getSession(true).setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, authException);
            
            redirectStrategy.sendRedirect(request, response, redirectUrl);
        }
    }
    
}


login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>登入</title>
  </head>
 
  <body>
      <table width="100%" height="100%" bgcolor="#FFFFFF">
          <tr align="center">
              <td>
              <div class="easyui-panel" title="登入" style="width:400px;height:auto;" align="center">
              <br/>
            <form action="${pageContext.request.contextPath}/j_spring_security_check" method="post">
                   <!-- 显示登入失败信息 ${sessionScope['SPRING_SECURITY_LAST_EXCEPTION']} -->
                <div style="display:${param.error == true ? 'block' : 'none'}">
                    <font color="red" size="10">登入失败:${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}</font>
                   </div>
                <div style="display:${param.error == 'denied' ? 'block' : 'none'}">
                    <font color="red" size="10">登入失败2:${SPRING_SECURITY_403_EXCEPTION.message}</font>
                   </div>                   
                帐号:<input name="j_username"><br/><br/>
                密码:<input type="password" name="j_password"><br/><br/>
                <input type="submit" value="登陆">
            </form>  
            </div>
              </td>
          </tr>
      </table>
  </body>
</html>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值