数据后台管理(四)权限控制
当我们在管理后台数据的时候需要对管理者的身份进行认证和授权,在该项目中用到的安全认证服务框架是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 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 extends GrantedAuthority> 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
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