你们好,本人最近在学习spring4,参考了书籍,写了一些demo(基于Servlet3.0,JDK7.0,Spring4,Tomcat8),欢迎讨论。html
在上个月发了一篇《Spring4纯注解启动》的博客http://www.javashuo.com/article/p-wjwzjchq-ma.htmljava
SpringSecurity是基于Spring的应用程序提供声明式安全保护的安全性框架。我能力有限,没法写出一篇详解,只能成功使用,逻辑大概明白而已,让你们见笑了。web
Maven:spring
<!-- spring-security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.1.RELEASE</version> </dependency>
主要类:(红色框内)sql
----------------------------------数据库
SpringSecurity借助一系列ServletFilter来提供各类安全性功能。安全
DelegatingFilterProxy是一个特殊的ServletFilter,它自己所作的工做并很少,只是将工做委托给了一个javax.servlet.Fitler实现类,这个实现类注册在Spring应用的上下文。cookie
它把Fitler的处理逻辑委托给Spring应用上下文中所定义的一个代理FitlerBean。框架
SecurityWebInitializer:ide
/** * 注册DelegatingFilterProxy * @author zoe * 2017年1月17日 * DelegatingFilterProxy是一个特殊的ServletFilter,它自己所作的工做并很少,只是将工做委托给了一个javax.servlet.Fitler实现类,这个实现类注册在Spring应用的上下文。 */ public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer { }
SecurityConfig:
package com.spittr.config; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.stereotype.Repository; import org.springframework.test.annotation.Repeat; /** * SpringSecurity启动配置类 * @author zoe * 2017年1月17日 */ @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private DataSource dataSource; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { /** 第一种将用户资料存储在内存中 **/ // auth.inMemoryAuthentication().withUser("user").password("123456").roles("USER").and().withUser("admin").password("admin").roles("USER","ADMIN"); /** 第二种使用关系型数据库 //这3个是安全框架默认的查询,前提是你的表跟它预期的同样,通常状况不会,因此要重写这类查询 //将默认sql查询替换要遵循查询的基本协议。全部查询都将用户名做为惟一的参数。 String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled " + "from users " + "where username = ?"; String DEF_AUTHORITIES_BY_USERNAME_QUERY = "select username,authority " + "from authorities " + "where username = ?"; String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY = "select g.id, g.group_name, ga.authority " + "from groups g, group_members gm, group_authorities ga " + "where gm.username = ? " + "and g.id = ga.group_id " + "and g.id = gm.group_id"; //查询用户名,密码,是否启用等,用来进行用户认证 auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(DEF_USERS_BY_USERNAME_QUERY); //查询用户所授予的权限,用来进行鉴权 0或多条 auth.jdbcAuthentication().dataSource(dataSource).authoritiesByUsernameQuery(DEF_AUTHORITIES_BY_USERNAME_QUERY); //查询用户群组的成员所授予的权限 0或多条 auth.jdbcAuthentication().dataSource(dataSource).groupAuthoritiesByUsername(DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY); **/ /** 第三种使用自定义认证,随意搭配方式 **/ UserDetailsService userDetailsService = new SecurtityUserDetailService(); auth.userDetailsService(userDetailsService); } @Override protected void configure(HttpSecurity http) throws Exception { ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests(); /**在authorizeRequests.antMatchers()的返回值中能够继续调用hasAnyAuthority()或者hasRole()这2个方法, 看起来一个是权限,一个是角色,可是仔细研究,你会发现,hasRole只是hasAnyAuthority它的一个简写版 因此在这个框架中,我认为能控制到角色这一层**/ //Specify that URLs require a particular authority. authorizeRequests.antMatchers("/form.do").hasAuthority("ROLL_ADMIN"); //Shortcut for specifying URLs require a particular role. If you do not want to have "ROLE_" automatically inserted see hasAuthority(String). authorizeRequests.antMatchers("/form.do").hasRole("ADMIN"); authorizeRequests.antMatchers("/form.do").authenticated();//authenticated()必须已经登陆了应用 authorizeRequests.anyRequest().permitAll();//容许其余请求经过 http.formLogin().loginPage("/login.html").loginProcessingUrl("/login.do").defaultSuccessUrl("/index.html")//登陆首页,默认验证经过后登陆index.html,验证请求/login.do .and().httpBasic()//开启httpBasic认证 .and().logout().logoutUrl("/logout.do").logoutSuccessUrl("/login.html")//登出后,跳转login.html .and().rememberMe().tokenValiditySeconds(3600).key("securityKey")//记住我 cookies 中会记录 一小时后失效 60*60 .and().csrf().disable();//禁用CSRF保护功能 } }
SecurtityUserDetailService:
/** * 自定义用户认证 * @author zoe * 2017年1月17日 */ public class SecurtityUserDetailService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); //模拟admin权限 authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); //模拟admin用户 SecurityUser securityUser = new SecurityUser("admin","admin",authorities); return securityUser; } }
SecurityUser:
/** * 安全认证用户 * @author zoe * 2017年1月17日 * 注意,在下方的一些boolean型的参数,默认是false,认证会失败 */ public class SecurityUser implements UserDetails { private String userName; private String password; private Collection<? extends GrantedAuthority> authorities; /** * */ private static final long serialVersionUID = 1L; public SecurityUser(String userName,String password){ this.userName = userName; this.password = password; } public SecurityUser(String userName,String password,Collection<? extends GrantedAuthority> authorities){ this.userName = userName; this.password = password; this.authorities = authorities; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return this.authorities; } @Override public String getPassword() { // TODO Auto-generated method stub return this.password; } @Override public String getUsername() { // TODO Auto-generated method stub return this.userName; } @Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { // TODO Auto-generated method stub return true; } }
login.html:
<form action="/login.do" method="post"> <div> <input type="text" name="username" class="username" placeholder="用户名" autocomplete="off" /> </div> <div> <input type="password" name="password" class="password" placeholder="密码" oncontextmenu="return false" onpaste="return false" /> </div> <div class="remember"> <input type="checkbox" name='remember-me'/><span>下次自动登陆</span> </div> <button id="submit" type="submit">登陆</button> </form>
index.html:
<a href="/logout.do">登出</a>