SpringSecurity的简单使用

1、导入依赖

 <dependencies>
 		//导入SpringSecurity
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>
        //导入SpringBoo-tWeb
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        //导入mysql
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.21version>
        dependency>
        //整合mybatis-spring
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.3.0version>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>org.springframework.securitygroupId>
            <artifactId>spring-security-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

2、使用MybatisPageHelperPro逆向生成实体类和接口、接口mapper

3、实体类实现UserDetails接口重写里面的方法

@Data
public class UserBean implements UserDetails {
    /**
    * 编号
    */
    private Integer userId;
        /**
    * 登陆名
    */
    private String username;
    ...........
    private List<SimpleGrantedAuthority> permission=new ArrayList<>();
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return permission;
    }
        /**
     * 密码是否过期
     * @return
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return credentialsNoExpired.equals(1);
    }

    /**
     * 账户是否被禁用
     * @return
     */
    @Override
    public boolean isEnabled() {
        return enabled.equals(1);
    }
}
/*
 * 自定义前端请求统一响应格式
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResponseData {
    private Integer code=200;
    private String msg="响应成功";
    private Object result;

    public ResponseData(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResponseData(Object result) {
        this.result = result;
    }
}
/**
 * 
 */
public class ResponseJsonUtil {

    /**
     * 统一在响应流中输入json字符串
     * @param response
     * @param data
     */
    public static  void  response(HttpServletResponse response, ResponseData data){
        ObjectMapper mapper=new ObjectMapper();
        try {
            String jsonStr=mapper.writeValueAsString(data);

            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/json;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(jsonStr);
            writer.flush();
            writer.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4、创建ServiceImpl类实现UserDetailsService接口重写loadUserByUsername方法

@Service
public class UserServiceImpl implements UserService, UserDetailsService {
    @Autowired
    private UserBeanMapper userBeanMapper;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名从数据库获取密码
        UserBean user = userBeanMapper.selectByUserName(username);
        if(null==user){
            throw new UsernameNotFoundException("用户名不存在");
        }
        //根据用户id从数据库获取用户的权限
        List<String> pers = userBeanMapper.selectPermissionCodeByUserId(user.getUserId());
        //将获取到的用户权限一个个放进List
        for(String per : pers){
            user.getPermission().add(new SimpleGrantedAuthority(per));
        }
        return user;
    }
}    

5、创建自定义Security配置类继承WebSecurityConfigurerAdapter抽象类


@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法级别的权限认证  默认是false
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserServiceImpl userService;
    /**
     * 配置用户信息,模拟内存用户数据
     *
     * @param auth
     * @throws Exception
     */
   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       //根据传入的自定义 UserDetailsService 添加身份验证。
       // 然后它返回一个DaoAuthenticationConfigurer对象以允许自定义身份验证
       auth.userDetailsService(userService);
   }


    @Autowired//注入身份认证失败处理器对象
    private AppAuthFailHandler appAuthFailHandler;
    @Autowired//注入身份认证成功处理器对象
    private AppAuthSuccessHandler appAuthSuccessHandler;
    @Autowired//注入访问拒绝处理器对象
    private AppAuthDenyHander appAuthDenyHander;
    @Autowired//注入退出登陆处理器对象
    private AppLogoutHandler appLogoutHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //身份验证
        http.formLogin() //返回一个基于表单的身份验证对象
               .successHandler(appAuthSuccessHandler)//登陆成功后执行的处理器
               .failureHandler(appAuthFailHandler);//登陆失败后执行的处理器

        //无权访问
        http.exceptionHandling().accessDeniedHandler(appAuthDenyHander);

        //退出登陆处理器
        http.logout().addLogoutHandler(appLogoutHandler);
        //配置路径拦截 的url的匹配规则
        http.authorizeRequests()
                //放行不需要权限的页面
                .mvcMatchers("/user/u1").anonymous()
                //任何路径要求必须认证之后才能访问
                .anyRequest().authenticated();

    }

    /*
     * 从 Spring5 开始,强制要求密码要加密
     * 如果非不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,
     * 但是不建议这么做,毕竟不安全。
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

6、自定义访问拒绝处理器,认证成功处理器、认证失败处理器,登出处理器,需要注入自定义Security配置类,交给Security处理

/*
 * 自定义访问拒绝处理器,实现AccessDeniedHandler接口
 */
@Component
public class AppAuthDenyHander implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        ResponseJsonUtil.response(response,new ResponseData(-1,"403"));
    }
}
/*
 * 身份认证成功处理器
 */
@Component
public class AppAuthSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        ResponseJsonUtil.response(response,new ResponseData(200,"登录成功",authentication));
    }
}
/**
 * 登录失败的处理器
 */
@Component
public class AppAuthFailHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        ResponseData result=new ResponseData(-1,"访问失败");

        if (exception instanceof BadCredentialsException){
            result.setMsg("密码错误");
        }else if (exception instanceof UsernameNotFoundException){
            result.setMsg("用户名不存在");
        }else if(exception instanceof DisabledException){
            result.setMsg("账户被禁用");
        }else if(exception instanceof AccountExpiredException){
            result.setMsg("账户过期");
        }else if(exception instanceof CredentialsExpiredException){
            result.setMsg("密码过期");
        }else if(exception instanceof LockedException){
            result.setMsg("账户被锁定");
        }else {
            result.setMsg("未知错误");
        }

        ResponseJsonUtil.response(response,result);
    }
}
/**
 * 登出的处理器
 */
@Component
public class AppLogoutHandler implements LogoutHandler {

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        ResponseJsonUtil.response(response,new ResponseData(200,"退出成功",authentication));
    }
}

7、 编写application.yml,配置数据源和mybatis

spring:
  datasource:
    password: root
    username: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.6.130:3306/security?useUnicode=true&useSSL=false&characterEncoding=UTF8&serverTimezone=UTC

mybatis:
  mapper-locations: classpath*:mybatis/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

8、编写Controller测试

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("add")
    @PreAuthorize("hasAnyAuthority('user:save')")//拥有save权限的用户可以访问
    public void add(HttpServletResponse response){
        ResponseData all = userService.findAll();
        ResponseJsonUtil.response(response,all);
    }
}

SpringSecurity的简单使用_第1张图片

你可能感兴趣的:(SpringSecurity,SpringSecurity)