当我们在管理后台数据的时候需要对管理者的身份进行认证和授权,在该项目中用到的安全认证服务框架是Spring Security。 1.Spring Security的简单入门 通过一个spring security的入门案例来了解使用该框架的基本步骤。 1.1使用IDEA新建一个webapp的maven工程,在pom.xml文件中引入spring security框架的相关坐标。 复制代码 1 2 3 5 4.0.0 6 7 club.nipengfei 8 spring_security_rumeng 9 1.0-SNAPSHOT 10 war 11 12 spring_security_rumeng Maven Webapp 13 14 http://www.example.com 15 16 17 5.0.2.RELEASE 18 5.0.1.RELEASE 19 20 21 22 23 org.springframework 24 spring-core 25 ${spring.version} 26 27 28 org.springframework 29 spring-web 30 ${spring.version} 31 32 33 org.springframework 34 spring-webmvc 35 ${spring.version} 36 37 38 org.springframework 39 spring-context-support 40 ${spring.version} 41 42 43 org.springframework 44 spring-test 45 ${spring.version} 46 47 48 org.springframework 49 spring-jdbc 50 ${spring.version} 51 52 53 54 org.springframework.security 55 spring-security-web 56 ${spring.security.version} 57 58 59 org.springframework.security 60 spring-security-config 61 ${spring.security.version} 62 63 64 javax.servlet 65 javax.servlet-api 66 3.1.0 67 provided 68 69 70 71 72 73 74 org.apache.maven.plugins 75 maven-compiler-plugin 76 3.2 77 78 1.8 79 1.8 80 UTF-8 81 82 83 84 org.apache.tomcat.maven 85 tomcat7-maven-plugin 86 87 88 8090 89 90 / 91 92 93 94 95 复制代码 1.2在web.xml中配置一个spring security的过滤器和引入spring security的核心配置文件。 复制代码 1 2 6 SpringSecurity314 7 8 9 contextConfigLocation 10 classpath:spring-security.xml 11 12 13 org.springframework.web.context.ContextLoaderListener 14 15 16 springSecurityFilterChain 17 org.springframework.web.filter.DelegatingFilterProxy 18 19 20 springSecurityFilterChain 21 /* 22 23 24 index.html 25 index.htm 26 index.jsp 27 default.html 28 default.htm 29 default.jsp 30 31 复制代码 1.3在resource资源路径下新建一个该框架的核心配置文件spring-security.xml 复制代码 1 2 9 10 14 15 18 19 20 21 22 24 26 27 28 29 复制代码 1.4入门案例总结 启动该入门案例发现直接跳转到了登录页面,但是我们并没有写有关登录的页面,这个页面是该框架本身自己的。 因为在核心配置文件中有开启spring security的默认的配置,当然也可以自定义登录页面。 当我们随意输入一个用户名"npf"和密码"1233"(配置文件中没有该用户名密码)时会出现如下提示 当我们输入用户名"admin"密码"admin"(配置文件中有该用户名密码但该角色不符合要求)时会出现如下提示,该提示表示权限不足。 当我们输入用户名"user"密码"user"时能够正常访问到index.jsp页面 上述简单入门案例存在明显不足之处,需要改进。 登录页面太简陋需要自定义 登录的账号一般在数据库中而不是在配置文件中 2.spring security在数据后台管理中的使用 为了确保数据的安全,在管理数据过程中需要对管理者的身份进行验证,并且让不同的管理者有不同的操作权限。 2.1与入门案例相似,在pom.xml文件中引入相应坐标,并在web.xml中配置一个spring security的过滤器和引入spring security的核心配置文件。 pom.xml web.xml 2.2配置spring security的核心配置文件 与入门案例相比,这里配置了不拦截的资源,自定义了登录页面,实现了退出操作,将原先定义在配置页面中的登录用户名和密码切换成在数据库中。 复制代码 1 2 9 10 11 12 13 14 15 16 17 22 23 24 25 26 27 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 复制代码 2.3使用数据库完成用户登录流程 下面是使用数据库完成认证操作的流程图 在Spring Security中如果想要使用数据进行认证操作,有很多种操作方式,这里我们介绍使用UserDetails、UserDetailsService来完成操作。 IUserService接口继承了UserDetailsService类,UserServiceImpl类实现了IUserService接口。 UserDetailsService 接口内有一个loadUserByUsername方法,返回的是UserDetails。 复制代码 1 public interface UserDetailsService { 2 // ~ Methods 3 // ======================================================================================================== 4 5 /** 6 * Locates the user based on the username. In the actual implementation, the search 7 * may possibly be case sensitive, or case insensitive depending on how the 8 * implementation instance is configured. In this case, the UserDetails 9 * object that comes back may have a username that is of a different case than what 10 * was actually requested.. 11 * 12 * @param username the username identifying the user whose data is required. 13 * 14 * @return a fully populated user record (never null) 15 * 16 * @throws UsernameNotFoundException if the user could not be found or the user has no 17 * GrantedAuthority 18 */ 19 UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; 20 } 复制代码 根据spring-security的核心配置文件,需要将UserServiceImpl类命名为"userService",并实现loadUserByUsername方法。 loadUserByUsername方法根据用户名从数据库中查询用户信息UserInfo,并将UserInfo的用户名,密码和角色信息作为User的构造参数。 复制代码 1 package club.nipengfei.service.impl; 2 3 import club.nipengfei.dao.IUserDao; 4 import club.nipengfei.domain.Role; 5 import club.nipengfei.domain.UserInfo; 6 import club.nipengfei.service.IUserService; 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.security.core.authority.SimpleGrantedAuthority; 9 import org.springframework.security.core.userdetails.User; 10 import org.springframework.security.core.userdetails.UserDetails; 11 import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 import org.springframework.stereotype.Service; 13 import org.springframework.transaction.annotation.Transactional; 14 15 import java.util.ArrayList; 16 import java.util.Collection; 17 import java.util.List; 18 19 @Service("userService") 20 @Transactional 21 public class UserServiceImpl implements IUserService { 22 23 @Autowired 24 private IUserDao userDao; 25 26 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 27 UserInfo userInfo = null; 28 try { 29 userInfo = userDao.findByUsername(username);31 } catch (Exception e) { 32 e.printStackTrace(); 33 } 34 // 处理自己的用户对象分装成UserDetails 35 // 该spring security的User实现了UserDetails 36 User user = new User(userInfo.getUsername(),userInfo.getPassword(),getAuthority(userInfo.getRoles()));38 return user; 39 } 40 41 public List getAuthority(List roles) { 42 List list = new ArrayList(); 43 for (Role role:roles){ 44 list.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName())); 45 } 46 return list; 47 } 48 } 复制代码 接口UserDetails,封装了当前认证用户的信息,但由于是一个接口,我们可以对其实现,也可以使用spring security提供的UserDetails实现类User完成操作 复制代码 1 public interface UserDetails extends Serializable { 2 Collection getAuthorities(); 3 String getPassword(); 4 String getUsername(); 5 boolean isAccountNonExpired(); 6 boolean isAccountNonLocked(); 7 boolean isCredentialsNonExpired(); 8 boolean isEnabled(); 9 } 复制代码 复制代码 1 public class User implements UserDetails, CredentialsContainer { 2 private String password; 3 private final String username; 4 private final Set authorities; 5 private final boolean accountNonExpired; //帐户是否过期 6 private final boolean accountNonLocked; //帐户是否锁定 7 private final boolea