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 进行修改即可。