SpringSecurity认证授权具体流程步骤(具体实例)

本案例是通过使用SpringSecurity来实现通过读取数据库中的数据,来完成认证授权的案例。

1. 向数据库中添加具体实例

创建出五个表,五个表之间的关系为:
sys_user:登录表,用于登陆后查询id
sys_user_role:用于根据用用户的id来查询到role_ id
sys_role_function:用于通过role_id来查询对应的fun_id
sys_function:用于通过fun_id来查询对应的方法,以及fun_code方法权限

DROP TABLE IF EXISTS `sys_function`;
CREATE TABLE `sys_function` (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `fun_name` varchar(50) DEFAULT NULL,
  `fun_url` varchar(50) DEFAULT NULL,
  `fun_code` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of sys_function
-- ----------------------------
INSERT INTO `sys_function` VALUES ('1', '商品列表查询', '/goods/list', 'goods:list');
INSERT INTO `sys_function` VALUES ('2', '商品添加', '/goods/add', 'goods:add');
INSERT INTO `sys_function` VALUES ('3', '商品删除', '/goods/del', 'goods:del');
INSERT INTO `sys_function` VALUES ('4', '商品更新', '/goods/update', 'goods:update');

-- ----------------------------
-- Table structure for `sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `rname` varchar(50) DEFAULT NULL,
  `rcode` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `rdesc` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '管理员', 'admin', null);
INSERT INTO `sys_role` VALUES ('2', '普通用户', 'user', null);

-- ----------------------------
-- Table structure for `sys_role_function`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_function`;
CREATE TABLE `sys_role_function` (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `role_id` varchar(50) DEFAULT NULL,
  `fun_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of sys_role_function
-- ----------------------------
INSERT INTO `sys_role_function` VALUES ('1', '1', '1');
INSERT INTO `sys_role_function` VALUES ('2', '1', '2');
INSERT INTO `sys_role_function` VALUES ('3', '1', '3');
INSERT INTO `sys_role_function` VALUES ('4', '1', '4');
INSERT INTO `sys_role_function` VALUES ('5', '2', '1');

-- ----------------------------
-- Table structure for `sys_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `uname` varchar(30) DEFAULT NULL,
  `upwd` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `uemail` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `uphone` char(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('a', 'admin', '$2a$10$tUBtEISZ/BkzQl0IJ6faOOZf6E1udcN9NsALobz2ofqooUPKUbm0K', null, '15516197242');
INSERT INTO `sys_user` VALUES ('b', 'anne', '$2a$10$tUBtEISZ/BkzQl0IJ6faOOZf6E1udcN9NsALobz2ofqooUPKUbm0K', null, '15516197241');

-- ----------------------------
-- Table structure for `sys_user_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `user_id` varchar(50) DEFAULT NULL,
  `role_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', 'a', '1');
INSERT INTO `sys_user_role` VALUES ('2', 'b', '2');

2.项目的具体结构

SpringSecurity认证授权具体流程步骤(具体实例)_第1张图片

3.添加相关的依赖,主要使用SpringBoot以及Mybatis_Plus,以及application.yml配置

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version> 3.5.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

application.yml:

server:
  port: 9007

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security_db?serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    #      连接池的类型
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 5
      max-active: 100
      min-idle: 10

4 .主要代码理解

①:项目中的mapper层,entiity层,service层以及实现类是通过mybatis_plus的相关注解,不再赘述。
②:创建对应的CusUserDetailsServiceImpl实现类,LoginUser实体类来完成对数据库中数据的读取。

LoginUser实体类:
该实体类要实现UserDetails的接口,来实现里面的方法,getAuthorities()方法主要是获取授权的权限:SimpleGrantedAuthority是查看GrantedAuthority的具体实现类来写的。(查看底层的逻辑)。

ArrayList strings = new ArrayList<>();
    for (Function function : functionList) {
        strings.add(new SimpleGrantedAuthority(function.getFunCode()));
    }
    return strings;
public class LoginUser implements UserDetails {
    private User user;
    private List<Function> functionList;

    public LoginUser(User user, List<Function> functionList) {
        this.user = user;
        this.functionList = functionList;
    }

    /**
     * 获取登录的用户 拥有哪些权限
     *
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        ArrayList<SimpleGrantedAuthority> strings = new ArrayList<>();
        for (Function function : functionList) {
            strings.add(new SimpleGrantedAuthority(function.getFunCode()));
        }
        return strings;
    }

    @Override
    public String getPassword() {
        return user.getUpwd();
    }

    @Override
    public String getUsername() {
        return user.getUname();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

CusUserDetailsServiceImpl实现类:
在这个类中,通过我们数据库中表的相关逻辑在实现类中实现相对应的方法。来查询我们所需要的loginUser。

@Service
public class CusUserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UserService userService;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private RoleFunctionService roleFunctionService;

    @Resource
    private FunctionService functionService;

    /**
     * 从何处 去加载一个用户
     *
     * @param s
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        User user = userService.getUserByName(s);
        String userId = user.getId();
//     根据用户id 去查询 角色
        List<String> roleIds = userRoleService.getRoleByUserId(userId);
//        根据roleId  去找 functionId
        List<String> functionIds = roleFunctionService.getFunctionByRoleIds(roleIds);
//        根据functionId 去找function
        List<Function> functions = functionService.listByIds(functionIds);
//
        LoginUser loginUser = new LoginUser(user, functions);
        return loginUser;
    }
}

③:完成SpringSecurity的配置类:
我们是基于session来实现的。前端使用postman来返回表单的数据。
SecurityConfig.java

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,jsr250Enabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }

    public NamePassFilter namePassFilter() throws Exception {
        NamePassFilter namePassFilter = new NamePassFilter();
        //交给拦截管理器来进行处理
        namePassFilter.setAuthenticationManager(authenticationManagerBean());
        //设置拦截路径为/login
        namePassFilter.setFilterProcessesUrl("/login");

//        认证成功
        namePassFilter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("status", "200");
                hashMap.put("msg", "认证成功");
                hashMap.put("auth", authentication);
                httpServletResponse.getWriter().write(new ObjectMapper().writeValueAsString(hashMap));
            }
        });
//        认证失败
        namePassFilter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
            @Override
            public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                httpServletResponse.getWriter().write("认证失败了" + e.getMessage());
            }
        });
        return namePassFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
        http.addFilterAt(namePassFilter(), UsernamePasswordAuthenticationFilter.class);
        http.csrf().disable();
    }
}

5.验证:

SpringSecurity认证授权具体流程步骤(具体实例)_第2张图片
SpringSecurity认证授权具体流程步骤(具体实例)_第3张图片

6:项目完整代码:

gitee:https://gitee.com/wangdaxia0089/spring-security-demo

你可能感兴趣的:(Java,java,spring)