基于spring boot和mongodb打造一套完整的权限架构(四)【完全集成security】

释放双眼,带上耳机,听听看~!

      在第二章的时候我们已经在我们的配置文件中设置了文件权限放行的功能,在本章我们将讲解如何基于mongodb数据库实现security,基于上一章我们编写的代码本章我们将实现security的权限控制。

      1、首先在我们的sys的entity目录底下我们新建一个UserRole、User以及QueryUser实体类,类信息如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1package com.mongo.sys.entity;
2
3
4import com.mongo.common.base.entity.QueryField;
5import org.bson.types.ObjectId;
6
7
8/*
9* 类描述:用户角色实体类
10* @auther linzf
11* @create 2018/3/30 0030
12*/
13public class UserRole {
14
15    private ObjectId id;
16    // 增加QueryField注解在buildBaseQuery构建Query查询条件的时候会自动将其加入到Query查询条件中
17    @QueryField
18    private String name;
19
20    private String roleName;
21
22
23    public String getId() {
24        return id.toString();
25    }
26
27    public void setId(String id) {
28        this.id = new ObjectId(id);
29    }
30
31    public String getName() {
32        return name;
33    }
34
35    public void setName(String name) {
36        this.name = name;
37    }
38
39    public String getRoleName() {
40        return roleName;
41    }
42
43    public void setRoleName(String roleName) {
44        this.roleName = roleName;
45    }
46
47}
48
49

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
1package com.mongo.sys.entity;
2
3
4import com.mongo.common.base.entity.QueryField;
5import org.bson.types.ObjectId;
6import org.springframework.security.core.GrantedAuthority;
7import org.springframework.security.core.authority.SimpleGrantedAuthority;
8import org.springframework.security.core.userdetails.UserDetails;
9
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.Date;
13import java.util.List;
14
15/*
16* 类描述:用户实体类
17* @auther linzf
18* @create 2018/3/30 0030
19*/
20public class User implements UserDetails {
21
22
23    private ObjectId id;
24    // 增加QueryField注解在buildBaseQuery构建Query查询条件的时候会自动将其加入到Query查询条件中
25    @QueryField
26    private String login;
27    private String password;
28    private String userName;
29    private String address;
30    private String job;
31    private Date birthDate;
32    private String city;
33    private String district;
34    private String province;
35    private String streetAddress;
36    private String state;
37    private String type;
38    private Date lastLoginDate;
39    // 用户角色信息
40    private List<UserRole> roles;
41    // 角色信息集合
42    private String roleArray;
43
44    public String getRoleArray() {
45        return roleArray;
46    }
47
48    public void setRoleArray(String roleArray) {
49        this.roleArray = roleArray;
50    }
51
52    @Override
53    public Collection<? extends GrantedAuthority> getAuthorities() {
54        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
55        if(this.getRoles()!=null){
56            List<UserRole> roles=this.getRoles();
57            for(UserRole role:roles){
58                if(role.getName()!=null){
59                    auths.add(new SimpleGrantedAuthority(role.getName()));
60                }
61            }
62        }
63        return auths;
64    }
65
66    public String getPassword() {
67        return password;
68    }
69
70    @Override
71    public String getUsername() {
72        return this.getLogin();
73    }
74
75    @Override
76    public boolean isAccountNonExpired() {
77        return true;
78    }
79
80    @Override
81    public boolean isAccountNonLocked() {
82        return true;
83    }
84
85    @Override
86    public boolean isCredentialsNonExpired() {
87        return true;
88    }
89
90    @Override
91    public boolean isEnabled() {
92        return true;
93    }
94
95    public String getId() {
96        return id.toString();
97    }
98
99    public void setId(String id) {
100        this.id = new ObjectId(id);
101    }
102
103    public String getLogin() {
104        return login;
105    }
106
107    public void setLogin(String login) {
108        this.login = login;
109    }
110
111    public void setPassword(String password) {
112        this.password = password;
113    }
114
115    public String getUserName() {
116        return userName;
117    }
118
119    public void setUserName(String userName) {
120        this.userName = userName;
121    }
122
123    public String getAddress() {
124        return address;
125    }
126
127    public void setAddress(String address) {
128        this.address = address;
129    }
130
131    public String getJob() {
132        return job;
133    }
134
135    public void setJob(String job) {
136        this.job = job;
137    }
138
139    public Date getBirthDate() {
140        return birthDate;
141    }
142
143    public void setBirthDate(Date birthDate) {
144        this.birthDate = birthDate;
145    }
146
147    public String getCity() {
148        return city;
149    }
150
151    public void setCity(String city) {
152        this.city = city;
153    }
154
155    public String getDistrict() {
156        return district;
157    }
158
159    public void setDistrict(String district) {
160        this.district = district;
161    }
162
163    public String getProvince() {
164        return province;
165    }
166
167    public void setProvince(String province) {
168        this.province = province;
169    }
170
171    public String getStreetAddress() {
172        return streetAddress;
173    }
174
175    public void setStreetAddress(String streetAddress) {
176        this.streetAddress = streetAddress;
177    }
178
179    public String getState() {
180        return state;
181    }
182
183    public void setState(String state) {
184        this.state = state;
185    }
186
187    public String getType() {
188        return type;
189    }
190
191    public void setType(String type) {
192        this.type = type;
193    }
194
195    public Date getLastLoginDate() {
196        return lastLoginDate;
197    }
198
199    public void setLastLoginDate(Date lastLoginDate) {
200        this.lastLoginDate = lastLoginDate;
201    }
202
203    public List<UserRole> getRoles() {
204        return roles;
205    }
206
207    public void setRoles(List<UserRole> roles) {
208        this.roles = roles;
209    }
210
211}
212
213

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
1package com.mongo.sys.entity;
2
3
4import com.mongo.common.base.entity.QueryBase;
5import com.mongo.common.base.entity.QueryField;
6import com.mongo.common.base.entity.QueryType;
7import org.bson.types.ObjectId;
8
9public class QueryUser extends QueryBase {
10
11    @QueryField(type = QueryType.LIKE)
12    private String userName;
13    @QueryField(type = QueryType.LIKE)
14    private String login;
15    @QueryField(type = QueryType.LIKE)
16    private String job;
17
18    private ObjectId groupId;
19
20    public String getGroupId() {
21        if(groupId==null){
22            return "";
23        }else{
24            return groupId.toString();
25        }
26
27    }
28
29    public void setGroupId(String groupId) {
30        if(groupId!=null&&!groupId.equals("")){
31            this.groupId = new ObjectId(groupId);
32        }else{
33            this.groupId = null;
34        }
35    }
36
37    public String getUserName() {
38        return userName;
39    }
40
41    public void setUserName(String userName) {
42        this.userName = userName;
43    }
44
45    public String getLogin() {
46        return login;
47    }
48
49    public void setLogin(String login) {
50        this.login = login;
51    }
52
53    public String getJob() {
54        return job;
55    }
56
57    public void setJob(String job) {
58        this.job = job;
59    }
60}
61
62

     
大家在构建实体类的时候,若我们的定义的字段类型是ObjectId类型那么大家记得set和get方法要做成如下的改造,否则将导致我们的程序在获取数据的时候报错:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1private ObjectId groupId;
2
3    public String getGroupId() {
4        if(groupId==null){
5            return "";
6        }else{
7            return groupId.toString();
8        }
9
10    }
11
12    public void setGroupId(String groupId) {
13        if(groupId!=null&&!groupId.equals("")){
14            this.groupId = new ObjectId(groupId);
15        }else{
16            this.groupId = null;
17        }
18    }
19

     ** **2、接着在我们的dao目录底下增加我们的UserDao数据库操作类,我们的
UserDao数据库操作类继承了我们上一章所编写的MongodbBaseDao抽象实现类,大家通过看下面的代码会发现,实际上我们并没有写多少代码,但是我们已经实现了用户的增删改查等这些通用的功能。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1package com.mongo.sys.dao;
2
3
4import com.mongo.common.base.dao.MongodbBaseDao;
5import com.mongo.common.base.entity.Pagination;
6import com.mongo.sys.entity.QueryUser;
7import com.mongo.sys.entity.User;
8import org.bson.types.ObjectId;
9import org.springframework.data.mongodb.core.query.Criteria;
10import org.springframework.data.mongodb.core.query.Query;
11import org.springframework.data.mongodb.core.query.Update;
12import org.springframework.stereotype.Component;
13
14import java.util.List;
15
16/*
17* 类描述:实现用户管理的dao
18* @auther linzf
19* @create 2018/3/30 0030
20*/
21@Component
22public class UserDao extends MongodbBaseDao<User,QueryUser> {
23
24
25
26    /**
27     * 功能描述:根据账号来获取用户信息
28     * @param login
29     * @return
30     */
31    public User findByLogin(String login){
32        Query query=new Query(Criteria.where("login").is(login));
33        User user =  mongoTemplate.findOne(query , User.class);
34        return user;
35    }
36
37    /**
38     * 功能描述:更新用户状态为可用或者不可用
39     * @param user
40     * @return
41     */
42    public void userControl(User user){
43        Query query=new Query(Criteria.where("id").is(user.getId()));
44        Update update= new Update().set("state", user.getState());
45        mongoTemplate.updateFirst(query,update,User.class);
46    }
47
48    @Override
49    public Pagination<User> findByPage(QueryUser queryUser) {
50        Query query = buildBaseQuery(queryUser);
51        if(queryUser.getGroupId()!=null&&!queryUser.getGroupId().equals("")){
52            query.addCriteria(Criteria.where("orgGroup.id").is(new ObjectId(queryUser.getGroupId())));
53        }
54        //获取总条数
55        long totalCount = this.mongoTemplate.count(query, this.getEntityClass());
56        //总页数
57        int totalPage = (int) (totalCount/queryUser.getLimit());
58        int skip = (queryUser.getPage()-1)*queryUser.getLimit();
59        Pagination<User> page = new Pagination(queryUser.getPage(), totalPage, (int)totalCount);
60        query.skip(skip);// skip相当于从那条记录开始
61        query.limit(queryUser.getLimit());// 从skip开始,取多少条记录
62        List<User> data = this.find(query);
63        page.build(data);//获取数据
64        return page;
65    }
66}
67
68

     
 3、开始集成我们的security,我们的spring boot的版本已经升级到了2.0版本,我们的security的版本也同步升级到了5.x版本,在5.x版本security已经废弃了好多5.x之前的东西,因此我们的security的配置也与之前的配置有了很多不同之处,比如我们的密码加密、设置放行目录和地址等,在这里就不再细说了,大家有兴趣可以直接去sprng security的官网直接了解新版本的不同之处,3.x标识的文件都是存放在config的security目录底下。

     
   3.1、LoginSuccessHandle:实现登陆成功以后根据不同的权限控制页面的跳转,代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1package com.mongo.common.config.security;
2
3import org.springframework.security.core.Authentication;
4import org.springframework.security.core.authority.AuthorityUtils;
5import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
6
7import javax.servlet.ServletException;
8import javax.servlet.http.HttpServletRequest;
9import javax.servlet.http.HttpServletResponse;
10import java.io.IOException;
11import java.util.Set;
12
13/*
14* 类描述:实现根据不同的权限实现登陆的时候页面的跳转
15* @auther linzf
16* @create 2018/04/13 0013
17*/
18public class LoginSuccessHandle implements AuthenticationSuccessHandler {
19    @Override
20    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
21        Set<String> roles = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
22        String path = request.getContextPath() ;
23        String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
24        if (roles.contains("ROLE_DINER")){
25            response.sendRedirect(basePath+"diningTable");
26            return;
27        }
28        response.sendRedirect(basePath+"main");
29    }
30}
31
32

     
   3.2、CustomUserService:主要实现自有的权限架构的用户的登陆业务逻辑的实现,代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
1package com.mongo.common.config.security;
2
3
4
5import com.mongo.sys.dao.UserDao;
6import com.mongo.sys.entity.User;
7import org.springframework.beans.factory.annotation.Autowired;
8import org.springframework.data.mongodb.core.query.Criteria;
9import org.springframework.data.mongodb.core.query.Query;
10import org.springframework.data.mongodb.core.query.Update;
11import org.springframework.security.authentication.LockedException;
12import org.springframework.security.core.userdetails.UserDetails;
13import org.springframework.security.core.userdetails.UserDetailsService;
14import org.springframework.security.core.userdetails.UsernameNotFoundException;
15
16import java.util.Date;
17
18/**
19 * Created by Administrator on 2018/04/17 0004.
20 */
21public class CustomUserService implements UserDetailsService {
22
23    @Autowired
24    private UserDao userDao;
25
26    @Override
27    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
28        User user = userDao.findByLogin(s);
29        if(user == null){
30            throw new UsernameNotFoundException("用户名不存在");
31        }
32        // 用户登陆以后更新用户的最迟登陆时间
33        Query query = new Query(Criteria.where("id").is(user.getId()));
34        Update update= new Update().set("lastLoginDate", new Date());
35        userDao.update(query,update);
36        // 自定义错误的文章说明的地址:http://blog.csdn.net/z69183787/article/details/21190639?locationNum=1&fps=1
37        if(user.getState()==null||user.getState().equalsIgnoreCase("0")){
38            throw new LockedException("用户账号被冻结,无法登陆请联系管理员!");
39        }
40        return user;
41    }
42}
43
44

     
   3.3、CustomPasswordEncoder:实现用户的密码加密,以及密码验证的功能,在security5.x版本已经弃用了之前的MD5密码加密功能,在该版本默认使用的是bcrypt加密功能进行密码的加密,若大家还是喜欢以前的密码加密功能,那就自己去实现密码的盐值加密,以及盐值的验证就可以了,此处默认使用的是bcrypt的加密方式进行密码的加密,代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1package com.mongo.common.config.security;
2
3
4import org.springframework.security.crypto.factory.PasswordEncoderFactories;
5import org.springframework.security.crypto.password.PasswordEncoder;
6
7/**
8 * spring-security登陆的密码进行bcrypt加密传到数据库
9 */
10public class CustomPasswordEncoder implements PasswordEncoder {
11    @Override
12    public String encode(CharSequence rawPassword) {
13        PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
14        return passwordEncoder.encode(rawPassword.toString());
15    }
16    @Override
17    public boolean matches(CharSequence rawPassword, String encodedPassword) {
18        PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
19        return passwordEncoder.matches(rawPassword.toString(),encodedPassword);
20    }
21
22}
23

     
   3.4、WebSecurityConfig:实现security的权限控制,以及页面放行,csrf(跨域访问)放行、iframe放行等权限的配置,代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
1package com.mongo.common.config.security;
2
3import org.springframework.context.annotation.Bean;
4import org.springframework.context.annotation.Configuration;
5import org.springframework.security.authentication.AuthenticationManager;
6import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
7import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
8import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
10import org.springframework.security.core.userdetails.UserDetailsService;
11import org.springframework.security.crypto.password.PasswordEncoder;
12
13/**
14 * 实现Security的配置
15 */
16@Configuration
17@EnableGlobalMethodSecurity(prePostEnabled=true)
18public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
19
20    /**
21     * 功能描述:实现自有的用户的登陆的验证
22     * @return
23     */
24    @Bean
25    UserDetailsService customUserService(){
26        return new CustomUserService();
27    }
28
29    /**
30     * 功能描述:实现密码的加密和验证
31     * @return
32     */
33    @Bean
34    PasswordEncoder passwordEncoder(){
35        return new CustomPasswordEncoder();
36    }
37
38    /**
39     * 功能描述:实现登陆成功以后页面的跳转
40     * @return
41     */
42    @Bean
43    LoginSuccessHandle loginSuccessHandle(){return new LoginSuccessHandle();}
44
45    @Override
46    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
47        auth.userDetailsService(customUserService()).passwordEncoder(passwordEncoder());
48
49    }
50
51    @Override
52    protected AuthenticationManager authenticationManager() throws Exception {
53        return super.authenticationManager();
54    }
55
56    /**
57     * 描述:csrf().disable()为了关闭跨域访问的限制,若不关闭则websocket无法与后台进行连接
58     * @param http
59     * @throws Exception
60     */
61    @Override
62    protected void configure(HttpSecurity http) throws Exception {
63        http.headers().frameOptions().disable();
64        // 设置放行目录
65        http.authorizeRequests().antMatchers("/api/*","/css/*","/js/*","/images/*","/fonts/*","/font-awesome/*").permitAll();
66        http.csrf().disable().authorizeRequests()
67                .anyRequest().authenticated()
68                .and()
69                .formLogin()
70                .loginPage("/login")
71                .defaultSuccessUrl("/main")
72                .successHandler(loginSuccessHandle())
73                .failureUrl("/login?error=true")
74                .permitAll()
75                .and()
76                .logout()
77                .logoutSuccessUrl("/login").
78                permitAll();
79    }
80
81}
82
83

     
 到此为止我们已经完成了spring security的集成了,接着我们集成springmvc的页面跳转部分,在我们的config的webmvc目录底下创建WebMvcConfig配置文件,代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1package com.mongo.common.config.webmvc;
2
3import org.springframework.context.annotation.Configuration;
4import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
5import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
6import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
7
8/**
9 * 类描述:springMVC的配置
10 */
11@Configuration
12public class WebMvcConfig extends WebMvcConfigurationSupport {
13
14    /**
15     * 功能描述:配置放行的静态文件的目录
16     * @param registry
17     */
18    @Override
19    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
20        super.addResourceHandlers(registry);
21        registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
22        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
23        registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/");
24        registry.addResourceHandler("/fonts/**").addResourceLocations("classpath:/static/fonts/");
25        registry.addResourceHandler("/font-awesome/**").addResourceLocations("classpath:/static/font-awesome/");
26    }
27
28    /**
29     * 重写方法描述:实现在url中输入相应的地址的时候直接跳转到某个地址
30     * @param registry
31     */
32    @Override
33    public void addViewControllers(ViewControllerRegistry registry) {
34        registry.addViewController("/login").setViewName("login");
35        registry.addViewController("/main").setViewName("main");
36        registry.addViewController("/error").setViewName("error");
37        registry.addViewController("/home").setViewName("home");
38        registry.addViewController("/upload").setViewName("/sys/upload/upload");
39        registry.addViewController("/dictList").setViewName("/sys/dict/dictList");
40        registry.addViewController("/userRoleList").setViewName("/sys/role/roleList");
41        registry.addViewController("/groupList").setViewName("/sys/orggroup/groupList");
42        registry.addViewController("/userList").setViewName("/sys/user/userList");
43        registry.addViewController("/treeList").setViewName("/sys/tree/treeList");
44    }
45
46}
47
48

     
 这样我们就完成了我们的spring security的全部集成,我们可以试着将我们的项目启动起来,大家直接访问以下的地址,若可以看到以下的页面说明我们的spring security已经集成完成了,静态的文件资源大家直接去我的github下面提供的地址去下载就好了,以及导入到mongodb数据库的文件也在我的当前工程的GitHub的db文件夹里,大家自己去拿,这里就不再贴出来了【导入mongodb数据库的脚本:
./mongoexport -u order -p hyll-2.0 -d test -c user -o /home/user.dat
】。

     
 接着大家输入账号:fjhyll和密码:123456,大家可以看到直接登陆成功画面说明我们已经完成了security的集成了。

       到此为止的GitHub项目地址:https://github.com/185594-5-27/csdn/tree/master-base-4

上一篇文章地址:基于spring boot和mongodb打造一套完整的权限架构(三)【抽象实现类和swagger的实现】

下一篇文章地址:基于spring boot和mongodb打造一套完整的权限架构(五)【集成用户模块、菜单模块、角色模块】

QQ交流群:578746866

给TA打赏
共{{data.count}}人
人已打赏
安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

安全运维

设计模式的设计原则

2021-12-12 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索