spring security 原理探索

1. 环境搭建

web.xml 配置 spring security过滤器:

  <!-- 配置 SpringSecurity 的 Filter -->
  <!-- DelegatingFilterProxy 在IOC容器里找到名字为springSecurityFilterChain 的bean -->
  <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 security配置文件:

        <security:http auto-config="true" use-expressions="true">
		<security:intercept-url pattern="/index.jsp" access="permitAll"/>
		<security:intercept-url pattern="/admin.jsp" access="hasRole('ROLE_ADMIN')"/>
	</security:http>
	
        <!-- 配置用户权限 -->
	<security:authentication-manager>
		<security:authentication-provider>
			<security:user-service>
				<security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN"></security:user>
				<security:user name="user" password="user" authorities="ROLE_USER"></security:user>
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>	

2. 测试与分析

<1> 访问 http://localhost/admin.jsp

spring Security 过滤器链:

FilterSecurityInterceptor 抛出 AccessDeniedException,ExceptionTransitionFilter进行异常处理,LoginUrlAuthenticationEntryPoint 把请求重定向到登录页面:

<2> 用户 user/user 登录:

FilterSecurityInterceptor 抛出 AccessDeniedException,ExceptionTransitionFilter进行异常处理,AccessDeniedHandler 转发到403。

<3> 用户 admin/admin 登录,访问成功。

<4> 访问 http://localhost/index.jsp

3. 自定义页面

自定义登录页面 index.jsp:

<form name='f' action='/spring_security_login' method='POST'>
    <table>
        <tr><td>用户名:</td><td><input type='text' name='username' value=''></td></tr>
        <tr><td>密码:</td><td><input type='password' name='password'/></td></tr>
        <tr><td colspan='2'><input name="submit" type="submit" value="登陆"/></td></tr>
    </table>
</form>
<a href="/logout">Logout</a>

spring-security.xml

<!--自定义登陆页面 -->
<security:form-login login-page="/login.jsp"
		     username-parameter="username"
		     password-parameter="password"
		     always-use-default-target="true"
		     default-target-url="/index.jsp"
		     authentication-failure-url="/failure.jsp"
		     login-processing-url="/spring_security_login"></security:form-login>

<!-- 自定义登出 -->
<security:logout logout-url="/logout"
		 logout-success-url="/index.jsp"
		 invalidate-session="true"></security:logout>

4. 退出操作

LogoutFilter 调用 SecurityContextLogoutHandler 注销session,

SimpleUrlLogoutSuccessHandler 请求重定向到 index.jsp

5. 若是需要从数据读取用户角色 和 接口的访问权限,则需要自定义策略

用户角色:

        <!-- 自定义UserDetailService接口实现 -->
	<bean id="myUserDetailService" class="com.dtdream.dmall.security.service.MyUserDetailService"></bean>
        <!-- 配置用户权限 -->
	<security:authentication-manager>
		<security:authentication-provider user-service-ref="myUserDetailService" >

			<!--<security:user-service>-->
				<!--<security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN"></security:user>-->
				<!--<security:user name="user" password="user" authorities="ROLE_USER"></security:user>-->
			<!--</security:user-service>-->

		</security:authentication-provider>
	</security:authentication-manager>
public class MyUserDetailService implements UserDetailsService {
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user;
        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        user = new User(username, "", true, true,
                true, true, authorities);

        return user;
    }
}

接口的访问权限:

public class MySecurityMetadataSource extends DefaultFilterInvocationSecurityMetadataSource {

    public MySecurityMetadataSource(LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap) {
        super(requestMap);
    }
}

定义工厂bean,向 MySecurityMetadataSource 注入 requestMap,

public class SecurityMetadataSourceFactoryBean implements FactoryBean<MySecurityMetadataSource> {
    
    public MySecurityMetadataSource getObject() throws Exception {

        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap();

        RequestMatcher requestMatcher = new AntPathRequestMatcher("/index.jsp");
        Collection<ConfigAttribute> configAttributes = new HashSet<ConfigAttribute>();
        configAttributes.add(new SecurityConfig("ROLE_USER"));

        requestMap.put(requestMatcher, configAttributes);

        requestMatcher = new AntPathRequestMatcher("/admin.jsp");
        configAttributes = new HashSet<ConfigAttribute>();
        configAttributes.add(new SecurityConfig("ROLE_ADMIN"));

        requestMap.put(requestMatcher, configAttributes);

        MySecurityMetadataSource mySecurityMetadataSource = new MySecurityMetadataSource(requestMap); 

        return mySecurityMetadataSource;
    }

    public Class<MySecurityMetadataSource> getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return false;
    }
}

spring-security.xml 配置:

        <!-- 工厂bean -->
	<bean id="securityMetadataSource"
		  class="com.dtdream.dmall.security.factorfy.SecurityMetadataSourceFactoryBean"></bean>

在IOC容器中把 securityMetadataSource 设置到 FilterSecurityInterceptor 中

web.xml 配置操作IOC容器的listener:

  <!-- 操作IOC容器的bean -->
  <listener>
    <listener-class>com.dtdream.dmall.security.listener.SpringSecurityListener</listener-class>
  </listener>
public class SpringSecurityListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent servletContextEvent) {

        // 获取IOC容器
        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());

        // 获取 securityMetadataSource 实例
        MySecurityMetadataSource mySecurityMetadataSource = (MySecurityMetadataSource) applicationContext.getBean("securityMetadataSource");

        // 获取 FilterSecurityInterceptor 实例
        FilterSecurityInterceptor filterSecurityInterceptor = applicationContext.getBean(FilterSecurityInterceptor.class);

        // 设置属性
        filterSecurityInterceptor.setSecurityMetadataSource(mySecurityMetadataSource);

    }

    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

springSecurity 集成 cas时,就是 需要配置 登录地址、ticket验证地址、登出地址,结合springSecurity的原理,需要对 LoginUrlAuthenticationEntryPoint 和 LogoutFilter 进行修改即可。

猜你喜欢

转载自blog.csdn.net/wjb214149306/article/details/81434460