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 
 2- spring.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
 29- package 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
 10- CREATE 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
 16- package 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
 8- package 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
 34- package 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
 28- DROP 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
 15- package 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
 29- DROP 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
 17- package 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
 52- package 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
 15- package 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
 12- package 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
 54- package 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
 29- package 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;
 }
 }
 评论



