使用springSecurity提供的login接口整合mybatis-plus并使用json格式登录

主要的点

  • springBoot整合mybatis-plus
  • 使用springSecurity做用户权限控制
  • 使用springSecurity提供的login接口整合mybatis-plus并使用json格式登录
  • mybatis-plus使用druid连接池

pom.xml配置




4.0.0
jar


    
        
            org.springframework.boot
            spring-boot-maven-plugin
            
                
                    
                        repackage
                        build-info
                    
                
            
        
    




    spring-boot-starter-parent
    org.springframework.boot
    2.5.1



    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
    
        org.springframework.boot
        spring-boot-starter-test
    
    
    
        org.springframework.boot
        spring-boot-starter-security
    
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
    
        com.alibaba
        druid-spring-boot-starter
        1.2.8
    
    
    
        mysql
        mysql-connector-java
    
    
    
        com.baomidou
        mybatis-plus-boot-starter
        3.4.3
    
    
    
        org.projectlombok
        lombok
    
    
    
        com.alibaba
        fastjson
        1.2.45
    
    
    
        org.zeroturnaround
        zt-zip
        1.13
    

springboot整合mybatis-plus

导入相关依赖后首先定义实体类

@TableName("user")

@Data
public class User implements UserDetails {

//表名与属性映射
@TableField("name")
private String name;//姓名
//表主键
@TableId
@TableField("id")
private String id;//学号
@TableField("classInt")
private int classInt;//班级

//通道状态为0时则已提交
@TableField("signs1")
private int signs1;//通道1
@TableField("signs2")
private int signs2;//通道2
@TableField("signs3")
private int signs3;//通道3
@TableField("imgPath")
private String imgPath;//图片路径

public User(String name, String id, int class_, int signs1, int signs2, int signs3, String imgPath) {
    this.name = name;
    this.id = id;
    classInt = class_;
    this.signs1 = signs1;
    this.signs2 = signs2;
    this.signs3 = signs3;
    this.imgPath = imgPath;
}

public User() {
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public int getClassInt() {
    return classInt;
}

public void setClassInt(int classInt) {
    this.classInt = classInt;
}

public int getSigns1() {
    return signs1;
}

public void setSigns1(int signs1) {
    this.signs1 = signs1;
}

public int getSigns2() {
    return signs2;
}

public void setSigns2(int signs2) {
    this.signs2 = signs2;
}

public int getSigns3() {
    return signs3;
}

public void setSigns3(int signs3) {
    this.signs3 = signs3;
}

public String getImgPath() {
    return imgPath;
}

public void setImgPath(String imgPath) {
    this.imgPath = imgPath;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return classInt == user.classInt && signs1 == user.signs1 && signs2 == user.signs2 && signs3 == user.signs3 && Objects.equals(name, user.name) && Objects.equals(id, user.id) && Objects.equals(imgPath, user.imgPath);
}

@Override
public int hashCode() {
    return Objects.hash(name, id, classInt, signs1, signs2, signs3, imgPath);
}

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", id='" + id + '\'' +
            ", Class_=" + classInt +
            ", signs1=" + signs1 +
            ", signs2=" + signs2 +
            ", signs3=" + signs3 +
            ", imgPath='" + imgPath + '\'' +
            '}';
}

}

编写对应的mapper接口

public interface UserMapper extends BaseMapper {

}

编写对应的server接口


public interface UserService extends IService {


}

编写server实现

@Service
public class UserServiceImpl extends ServiceImpl implements UserService, UserDetailsService {


}

这时可以通过server接口来直接使用mybatis-plus内置的方法
如果需要添加自己定义的方法
则要在mapper接口中定义这个方法
通过注解或者xml文件编写sql语句,然后在server中定义方法,最后在server实现类中通过@Resource注解来填充mapper变量通过调用mapper来完成自定义的方法

使用springSecurity做用户权限控制

导入相关依赖
springSecurity默认使用表单提交数据,这里想要修改成使用通过fetch使用json格式的数据来通过登录验证
为此需要在登录的用户实体类实现 UserDetails,实现方法

@Override
    public Collection getAuthorities() {
        List authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_user"));

        return authorities;
    }

    //这里设置密码为名字
    @Override
    public String getPassword() {
        return name;
    }

    //唯一用户名
    @Override
    public String getUsername() {
        return id;
    }

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

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

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

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

自定义CustomAuthenticationFilter类,继承UsernamePasswordAuthenticationFilter
重写方法attemptAuthentication()用来替换掉springSecurity提供的默认方法来实现使用json格式登录

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    /**
     * 替换掉SpringSecurity中的attemptAuthentication方法
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
                || request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
            ObjectMapper mapper = new ObjectMapper();
            UsernamePasswordAuthenticationToken authRequest = null;
            try (InputStream is = request.getInputStream()) {
                Map authenticationBean = mapper.readValue(is, Map.class);
                authRequest = new UsernamePasswordAuthenticationToken(
                        authenticationBean.get("username"), authenticationBean.get("password"));
            } catch (IOException e) {
                e.printStackTrace();
                authRequest = new UsernamePasswordAuthenticationToken(
                        "", "");
            } finally {
                setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            }
        } else {
            return super.attemptAuthentication(request, response);
        }
    }
}

在登录用户的实体类的serverImpl上实现UserDetailsService

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        if (s == null || s.trim().length() == 0) {
            return null;
        }

        User user = userService.getById(s);

        if (null == user) {
            return adminServer.loadUserByUsername(s);
        }else {
            return user;
        }
    }

在Security类上configure()方法

    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

设置使用json格式

 //重新配置登录模块,使用JSON
    @Bean
    CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        //配置登录成功响应
        filter.setAuthenticationSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.setStatus(HttpServletResponse.SC_OK);
            //登录成功后的用户信息
            Object principal = authentication.getPrincipal();

            PrintWriter out = httpServletResponse.getWriter();

            out.write(new ObjectMapper().writeValueAsString(principal));
            out.flush();
            out.close();
        });

        filter.setAuthenticationFailureHandler((httpServletRequest, httpServletResponse, e) -> {
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = httpServletResponse.getWriter();

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("status", "登录失败");

            out.write(jsonObject.toJSONString());
            out.flush();
            out.close();
        });


        //设置身份验证器
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

下面附上Security配置类上的全部代码


@Configuration
@EnableWebSecurity
public class Security extends WebSecurityConfigurerAdapter {
    @Autowired
    UserServiceImpl userService;

    //角色继承
    @Bean
    RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
        //注意中间有空格
        hierarchy.setHierarchy("ROLE_root > ROLE_admin");
        return hierarchy;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/user/**").hasRole("user")
                .antMatchers("/admin/**").hasRole("admin")
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .and()
                //关闭csrf保护,会有安全问题,但是在这里不重要
                .csrf().disable().exceptionHandling()
                //没有登录就访问需要登录的接口的回调
                .authenticationEntryPoint((request, response, authException) -> {
                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    response.setCharacterEncoding("UTF-8");
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

                    PrintWriter out = response.getWriter();

                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("status", "尚未登录,请先登录");

                    out.write(jsonObject.toJSONString());
                    out.flush();
                    out.close();
                })
                .accessDeniedHandler((request, response, authException)->{
                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    response.setCharacterEncoding("UTF-8");
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

                    PrintWriter out = response.getWriter();

                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("status", "没有权限");

                    out.write(jsonObject.toJSONString());
                    out.flush();
                    out.close();
                })
                .and()
                //退出登录状态的回调
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler((request, response, authentication) -> {
                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    response.setCharacterEncoding("UTF-8");
                    response.setStatus(HttpServletResponse.SC_OK);
                    PrintWriter out = response.getWriter();

                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("status", "注销成功");

                    out.write(jsonObject.toJSONString());
                    out.flush();
                    out.close();
                })
                .deleteCookies()
                .permitAll();

        http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }


    //密码加密
    @Bean
    PasswordEncoder passwordEncoder() {
        // BCryptPasswordEncoder:Spring Security 提供的加密工具,可快速实现加密加盐
        //现在暂时使用明文存储

        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //用来配置忽略掉的 URL 地址,一般对于静态文件,我们可以采用此操作
        web.ignoring().antMatchers("/js/**", "/css/**");
    }

    //重新配置登录模块,使用JSON
    @Bean
    CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        //配置登录成功响应
        filter.setAuthenticationSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.setStatus(HttpServletResponse.SC_OK);
            //登录成功后的用户信息
            Object principal = authentication.getPrincipal();

            PrintWriter out = httpServletResponse.getWriter();

            out.write(new ObjectMapper().writeValueAsString(principal));
            out.flush();
            out.close();
        });

        filter.setAuthenticationFailureHandler((httpServletRequest, httpServletResponse, e) -> {
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = httpServletResponse.getWriter();

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("status", "登录失败");

            out.write(jsonObject.toJSONString());
            out.flush();
            out.close();
        });


        //设置身份验证器
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }


}



mybatis-plus使用druid数据源
druid的配置类

@Configuration
public class DruidConfiguration {
    @Bean
    public ServletRegistrationBean druidServlet() {
        //后台服务
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new StatViewServlet());
        //访问后台地址
        servletRegistrationBean.addUrlMappings("/druid/*");
        //后台的登录帐密
        Map initParameters = new HashMap<>();
        initParameters.put("loginUsername", "tanjunwen");
        initParameters.put("loginPassword", "qQ1143042332");
        //ip白名单,为空时,代码谁都可以访问
        initParameters.put("allow", "");
        //ip黑名单
        //initParameters.put("deny","");
        //设置初始化参数
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;
    }

    //定义数据源
    @ConfigurationProperties(prefix = "spring.datasource.druid")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    //配置 Druid 监控 之  web 监控的 filter
    //WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
    @Bean
    public FilterRegistrationBean webStatFilter() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());

        //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
        Map initParams = new HashMap<>();
        initParams.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,/jdbc/*");
        bean.setInitParameters(initParams);
        //"/*" 表示过滤所有请求
        bean.setUrlPatterns(Arrays.asList("/*"));
        return bean;
    }

}

在application.yml文件中添加以下的配置信息

datasource:
    druid:
      #连接信息
      url: 你的数据库连接地址
      username: tanjunwen
      password: qQ1143042332
      driver-class-name: com.mysql.jdbc.Driver
      #连接池配置
      min-idle: 3
      initial-size: 3
      max-active: 5
      #配置获取连接等待超时时间
      max-wait: 60000
      #间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      time-between-eviction-runs-millis: 120000
      #配置一个连接在池中最小的生存时间
      min-evictable-idle-time-millis: 300000
      #测试连接
      validation-query: SELECT 1 from DUAL
      #申请连接时检测
      test-while-idle: true
      #获取连接时执行检测
      test-on-borrow: false
      #归还连接时检测
      test-on-return: false
      #是否开启PSCache,PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭
      pool-prepared-statements: false
      #监控
      filter:
        wall:
          enabled: true

你可能感兴趣的:(使用springSecurity提供的login接口整合mybatis-plus并使用json格式登录)