SpringBoot整合SpringSecurity
1. SpringBoot整合SpringSecurity
Spring Security 是 Spring 家族中的一个安全管理框架,提供了权限的解决方案,通过一些简单的配置以及代码,就可以轻松实现。
安全:认证+授权
1.1 导入依赖
1 | <dependency> |
1.2 启动访问接口
1 | //启动会在控制台出现 |
同时访问http://localhost:8080/user/findAll ,会出现一个登陆页面
这时候,用户名输入user,密码输入上方控制台打印的密码,即可登录,并且正常访问接口。
1.3 登录的用户名/密码
对登录的用户名/密码进行配置,有三种不同的方式:
在 application.properties 中进行配置
1
2spring.security.user.name=admin
spring.security.user.password=mszlu通过 Java 代码配置在内存中
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
29package com.mszlu.union.config;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//下面这两行配置表示在内存中配置了两个用户
auth.inMemoryAuthentication()
.withUser("admin").roles("admin").password("$2a$10$2UaOufuypWR1TASuso2S6.u6TGL7nuAGCsb4RZ5X2SMEuelwQBToO")
.and()
.withUser("user").roles("user").password("$2a$10$2UaOufuypWR1TASuso2S6.u6TGL7nuAGCsb4RZ5X2SMEuelwQBToO");
}
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public static void main(String[] args) {
String mszlu = new BCryptPasswordEncoder().encode("mszlu");
System.out.println(mszlu);
}
}
- 通过 Java 从数据库中加载
1.4 登录配置
1 |
|
1.4.1 自定义登录
1 |
|
1.5 数据库访问认证和授权
1.5.1 登录认证
表结构
1
2
3
4
5
6
7
8
9
10CREATE TABLE `admin_user` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`create_time` bigint(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
INSERT INTO `admin_user`(`id`, `username`, `password`, `create_time`) VALUES (1, 'admin', '$2a$10$2UaOufuypWR1TASuso2S6.u6TGL7nuAGCsb4RZ5X2SMEuelwQBToO', 1622711132975);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package com.mszlu.union.pojo;
import lombok.Data;
public class AdminUser {
private Long id;
private String username;
private String password;
private Long createTime;
}1
2
3
4
5
6
7
8package com.mszlu.union.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.union.pojo.AdminUser;
public interface AdminUserMapper extends BaseMapper<AdminUser> {
}
实现UserDetailService接口
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
34package com.mszlu.union.security;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mszlu.union.mapper.AdminUserMapper;
import com.mszlu.union.pojo.AdminUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
public class SecurityUserService implements UserDetailsService {
private AdminUserMapper adminUserMapper;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AdminUser::getUsername,username).last("limit 1");
AdminUser adminUser = this.adminUserMapper.selectOne(queryWrapper);
if (adminUser == null){
throw new UsernameNotFoundException("用户名不存在");
}
List<GrantedAuthority> authorityList = new ArrayList<>();
UserDetails userDetails = new User(username,adminUser.getPassword(),authorityList);
return userDetails;
}
}
在配置中添加使用UserDetailService
1
2
3
4
5
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(securityUserService);
//...
}
1.5.2 授权
权限相关表结构
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
28DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`role_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`role_keyword` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '管理员', '管理员', 'ADMIN');
INSERT INTO `role` VALUES (2, '运营', '运营部门', 'BUSINESS');
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`user_id` bigint(0) NOT NULL,
`role_id` int(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `user_id`(`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1, 1);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.mszlu.union.pojo;
import lombok.Data;
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
private String roleKeyword;
}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
29DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`permission_keyword` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (1, '查询全部', '查询全部', 'USER_FINDALL', '/user/findAll');
INSERT INTO `permission` VALUES (2, '年龄查询', '年龄查询', 'USER_FINDAGE', '/user/findAge');
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`role_id` int(0) NOT NULL,
`permission_id` int(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `role_id`(`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES (1, 1, 1);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.mszlu.union.pojo;
import lombok.Data;
public class Permission {
private Integer id;
private String name;
private String desc;
private String permissionKeyword;
private String path;
}
在UserDetailService的接口实现中,查询用户的权限
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
52package com.mszlu.union.security;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mszlu.union.mapper.AdminUserMapper;
import com.mszlu.union.mapper.PermissionMapper;
import com.mszlu.union.mapper.RoleMapper;
import com.mszlu.union.pojo.AdminUser;
import com.mszlu.union.pojo.Permission;
import com.mszlu.union.pojo.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
public class SecurityUserService implements UserDetailsService {
private AdminUserMapper adminUserMapper;
private RoleMapper roleMapper;
private PermissionMapper permissionMapper;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AdminUser::getUsername,username).last("limit 1");
AdminUser adminUser = this.adminUserMapper.selectOne(queryWrapper);
if (adminUser == null){
throw new UsernameNotFoundException("用户名不存在");
}
List<GrantedAuthority> authorityList = new ArrayList<>();
//查询角色和角色对应的权限 并赋予当前的登录用户,并告知spring security框架
List<Role> roleList = roleMapper.findRoleListByUserId(adminUser.getId());
for (Role role : roleList) {
List<Permission> permissionList = permissionMapper.findPermissionByRole(role.getId());
authorityList.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleKeyword()));
for (Permission permission : permissionList) {
authorityList.add(new SimpleGrantedAuthority(permission.getPermissionKeyword()));
}
}
UserDetails userDetails = new User(username,adminUser.getPassword(),authorityList);
return userDetails;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.mszlu.union.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.union.pojo.Permission;
import com.mszlu.union.pojo.Role;
import java.util.List;
public interface PermissionMapper extends BaseMapper<Permission> {
List<Permission> findPermissionByRole(Integer roleId);
}1
2
3
4
5
6
7
8
9
10
11
12package com.mszlu.union.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.union.pojo.Role;
import java.util.List;
public interface RoleMapper extends BaseMapper<Role> {
List<Role> findRoleListByUserId(Long userId);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--MyBatis配置文件-->
<mapper namespace="com.mszlu.union.mapper.PermissionMapper">
<resultMap id="perMap" type="com.mszlu.union.pojo.Permission">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="desc" property="desc"/>
<result column="permission_keyword" property="permissionKeyword"/>
<result column="path" property="path"/>
</resultMap>
<select id="findPermissionByRole" parameterType="int" resultMap="perMap">
select * from permission where id in (select permission_id from role_permission where role_id=#{roleId})
</select>
</mapper>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--MyBatis配置文件-->
<mapper namespace="com.mszlu.union.mapper.RoleMapper">
<resultMap id="roleMap" type="com.mszlu.union.pojo.Role">
<id column="id" property="id"/>
<result column="role_name" property="roleName"/>
<result column="role_desc" property="roleDesc"/>
<result column="role_keyword" property="roleKeyword"/>
</resultMap>
<select id="findRoleListByUserId" parameterType="long" resultMap="roleMap">
select * from role where id in (select role_id from user_role where user_id=#{userId})
</select>
</mapper>
在接口上配置权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public List<User> findAll(){
return userService.findAll();
}
public List<User> findAge(){
return userService.findAge();
}
public User findById({ Long id)
return userService.findById(id);
}
在配置上开启权限认证
1
2
3
public class SecurityConfig extends WebSecurityConfigurerAdapter {}
1.5.3 另一种方式进行授权
修改配置
1
2
3
4
5
6
7
8
9
10
protected void configure(HttpSecurity http) throws Exception {
// http.userDetailsService(securityUserService);
http.authorizeRequests() //开启登录认证
// .antMatchers("/user/findAll").hasRole("admin") //访问接口需要admin的角色
.antMatchers("/login").permitAll()
//使用访问控制 自己实现service处理,会接收两个参数
.anyRequest().access("@authService.auth(request,authentication)")
// .anyRequest().authenticated() // 其他所有的请求 只需要登录即可
}
编写AuthService的auth方法、
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
54package com.mszlu.union.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mszlu.union.mapper.AdminUserMapper;
import com.mszlu.union.mapper.PermissionMapper;
import com.mszlu.union.mapper.RoleMapper;
import com.mszlu.union.mapper.UserMapper;
import com.mszlu.union.pojo.AdminUser;
import com.mszlu.union.pojo.Permission;
import com.mszlu.union.pojo.Role;
import com.mszlu.union.security.MySimpleGrantedAuthority;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class AuthService {
private AdminUserMapper adminUserMapper;
private RoleMapper roleMapper;
private PermissionMapper permissionMapper;
public boolean auth(HttpServletRequest request, Authentication authentication){
String requestURI = request.getRequestURI();
Object principal = authentication.getPrincipal();
if (principal == null || "anonymousUser".equals(principal)){
//未登录
return false;
}
UserDetails userDetails = (UserDetails) principal;
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
for (GrantedAuthority authority : authorities) {
MySimpleGrantedAuthority grantedAuthority = (MySimpleGrantedAuthority) authority;
String[] paths = StringUtils.split(requestURI, "?");
if (paths[0].equals(grantedAuthority.getPath())){
return true;
}
}
return false;
}
}
修改UserDetailService中 授权的实现,实现自定义的授权类,增加path属性
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
29package com.mszlu.union.security;
import org.springframework.security.core.GrantedAuthority;
public class MySimpleGrantedAuthority implements GrantedAuthority {
private String authority;
private String path;
public MySimpleGrantedAuthority(){}
public MySimpleGrantedAuthority(String authority){
this.authority = authority;
}
public MySimpleGrantedAuthority(String authority,String path){
this.authority = authority;
this.path = path;
}
public String getAuthority() {
return authority;
}
public String getPath() {
return path;
}
}
评论