Springboot、MybatisPlus、SpringSecurity整合(前后端分离)

2023-01-09 21:15:15

做了一个小项目,自己总结一下

1、导入需要导入的主要的包(本人自己的版本,其余的可以自己配)

  • springboot,版本2.2.1.RELEASE
  • springsecurity,版本用springboot自带的
  • mysql-connector-java,版本8以上都行
  • mybatis-plus,版本3.5.1

2、配置application.properties(这个应该都会,不解释)

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/feiyi?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

3、实体类书写

我这用了两个实体类(指的是与security相关的表),一个是UserConfig,还有一个是UserPojo,其中,属性看下:
UserConfig:

@NoArgsConstructor
@AllArgsConstructor
@Data
@TableName("user_config")
public class UserConfig implements Serializable {
    private static final long serialVersionUID = 1L;
    // 自增主键id
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    // 就是所说的username,因为我们是用邮箱注册的
    private String email;
    // 密码
    private String password;
    // 网名,项目需要
    private String webName;
    // 身份
    private String role;
}

表userconfig在数据库中的内容
在这里插入图片描述

UserPojo:(用于security的需要)
这里需要实现UserDetails这个接口,因为在实现UserDetailsServiceloadUserByUsername接口时需要返回一个UserDetails类,这个UserPojo就表示重写(自定义)的一个UserDetails类


@NoArgsConstructor
@Data
public class UserPojo implements UserDetails {
    private Integer id;//主键
    private String email;//与username作用相同
    private String password;//密码
    private String role;//角色
    private List<GrantedAuthority> grantedAuthorities;//认证区间(我是这么理解的)

    public UserPojo(Integer id, String email, String password, String role, List<GrantedAuthority> grantedAuthorities) {
        this.id = id;
        this.email = email;
        this.password = password;
        this.role = role;
        this.grantedAuthorities = grantedAuthorities;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return grantedAuthorities;
    }
    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return email;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    }
}

4、MybatisPlusSecurityConfig(类名,随便取,注重规范就行) 实现UserDetailsService接口

这个接口用于对传入的UserName进行对照,看数据库中是否有该字段,这里的查询的过程按照规范应该是放在Service里,由于行数太少,我就直接放在了下面。


@Component
public class MybatisPlusSecurityConfig implements UserDetailsService {

    @Resource
    private IUserConfigService userConfigService;//这个是Mybatis-plus中用于下方对用户名的查询中会使用的,会Mybatis-plus的就懂,不解释
    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        QueryWrapper<UserConfig> userConfigQueryWrapper = new QueryWrapper<>();
        userConfigQueryWrapper.eq("email", email);
        UserConfig theOne = userConfigService.getOne(userConfigQueryWrapper);//这里查询出目标UserConfig对象,有则不为null

        List<GrantedAuthority> grantedAuthorities = null;//用于存储认证机制

        System.out.println("theOne"+theOne);

        if(theOne != null){
            grantedAuthorities = new ArrayList<>();
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+theOne.getRole());
            grantedAuthorities.add(grantedAuthority);//将角色放入列表中
        }else{
            throw new UsernameNotFoundException("邮箱或者密码错误!");//如果所查出来的userConfig为空,则抛出异常
        }
        return new UserPojo(
                    theOne.getId(),
                    theOne.getEmail(),
                    theOne.getPassword(),
                    theOne.getRole(),
                    grantedAuthorities);//返回一个实现了UserDetails类的UserPojo类(本质上就是一个UserDetails类)
    }
}

5、设计成功响应,以及失败相应

实现登入成功处理接口AuthenticationSuccessHandler


// 验证成功案例
@Component
public class SuccessAuthentication implements AuthenticationSuccessHandler {

    @Resource
    private IUserConfigService userConfigService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        response.setContentType("text/json;charset=UTF-8");
        ServletOutputStream outputStream = response.getOutputStream();
        
        Result result = Result.ok(new String("登入成功"));

        outputStream.write(JSON.toJSONString(result).getBytes());//在这里设置需要返回的值,需要什么自己设定,正常会带上token,是json格式
        outputStream.flush();
        outputStream.close();
    }
}

实现登入失败处理接口AuthenticationFailureHandler


// 验证失败案例
@Component
public class FailAuthentication implements AuthenticationFailureHandler {

    private Result result;

    public void setResult(Result result){
        this.result = result;
    }

    public FailAuthentication(){
    //默认方式
        this.result = Result.error(new String("登入失败"));
    }

    /**
     *
     * @param request 请求应答
     * @param response 应答对象
     * @param e
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException e) throws IOException, ServletException {

        ServletOutputStream outputStream = response.getOutputStream();

        //处理编码方式,防止中文乱码的情况
        response.setContentType("application/json;charset=utf-8");

        outputStream.write(JSON.toJSONString(result).getBytes());
        outputStream.flush();
        outputStream.close();
    }
}

6、MySecurityConfig (类名,随便取,注重规范就行)实现WebSecurityConfigurerAdapter接口

这个类最主要的功能就是授权、认证(包括对接口、静态资源、其他URL的授权、认证),还有一些其他的配置,反正他就是一个配置类。

/**
 * @EnableGlobalMethodSecurity:启动方法级别的认证
 *      (prePostEnabled = true):默认是false
 *          true:表示可以启@PreAuthorise注解和 @PostAuthorise
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
// 开启基于方法的安全认证机制,也就是说在web层的controller启用注解机制的安全确认
// 只有加了@EnableGlobalMethodSecurity(prePostEnabled=true) 那么在上面使用的 @PreAuthorize(“hasAuthority(‘admin’)”)才会生效
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

	// 这个接口实现了用户名的认证
    @Resource
    private MyUserConfigDetailService myUserConfigDetailService;

	// 注入成功案例
    @Resource
    private AuthenticationSuccessHandler authenticationSuccessHandler;

	// 注入失败案例
    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;

    /**
     * 用于对认证进行处理(核心)
     * <p>
     * AuthenticationManager: 用于认证的核心接口.
     * AuthenticationManagerBuilder: 用于构建AuthenticationManager接口对象的工具.
     * ProviderManager: AuthenticationManager接口的默认实现类.
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //        内置(默认)的认证规则:
        auth.userDetailsService(myUserConfigDetailService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.cors().and().csrf().disable();//前后端分离跨域问题

        // 登录页面相关配置
        http.authorizeRequests().and().formLogin()//允许表单登录
                .loginPage("/api/login") //自定义登录页面
                .usernameParameter("email")//使用自定义的username
                .successHandler(authenticationSuccessHandler) //登录成功处理逻辑
                .failureHandler(authenticationFailureHandler); //登录失败处理逻辑

        http.authorizeRequests()
                // 对某个接口,需要该账号有什么样的角色
                .antMatchers("/api/normal/**").hasAnyRole("normal","admin","superAdmin")
                .antMatchers("/api/admin/**").hasAnyRole("admin","superAdmin")
                .antMatchers("/api/superAdmin/**").hasAnyRole("superAdmin")
                .and()
                .formLogin();
    }

    /**
     * 用于配置一些拦截的资源
     *
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //忽略resources 下的所有静态资源
        web.ignoring().antMatchers("/static/**", "/static/index.html", "/index.html","/ap1/login");
    }
}

6、测试

在这里插入图片描述

  • 作者:老哥不老
  • 原文链接:https://blog.csdn.net/luocong321/article/details/125607984
    更新时间:2023-01-09 21:15:15