Spring Security

1. 概述

  • springSecurity是基于Spring生态圈,用于提供 安全访问控制 的解决方案框架。SpringSecurity的安全管理有两个重要概念:认证(Authentication)授权(Authorization)

  • springBoot对SpringSecurity进行了整合支持,并提供了通用的自动化配置,从而实现了SpringSecurity中包含的多数功能;

2. 认证

springSecurity登录认证主要涉及两个重要接口,UserDetailService UserDetails

  • UserDetailService接口主要定义了一个方法 loadUserByUsername(String userName)用于完成用户信息的查询。userName就是用户登录名,登录认证时,需要自定义一个实现类来实现UserDetailService接口,完成数据库查询,该接口返回UserDetails接口的对象;

  • UserDetails接口主要用来封装认证成功的用户信息,需要自定义一个用户对象来实现UserDetails接口,即UserDetailService返回的用户信息;

1)认证步骤

1. 添加依赖:spring-boot-starter-security

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

2.自定义UserDetails类:当实体对象字段不满足要求时需自定义UserDetails接口的实现类; 

@Data
@TableName("sys_user")
public class User implements Serializable, UserDetails { 
    
    //省略原有的属性......
    
    /**
     * 帐户是否过期(1 未过期,0已过期)
     */
    private boolean isAccountNonExpired = true;
    
    /**
     * 帐户是否被锁定(1 未过期,0已过期)
     */
    private boolean isAccountNonLocked = true;
    
    /**
     * 密码是否过期(1 未过期,0已过期)
     */
    private boolean isCredentialsNonExpired = true;
    
    /**
     * 帐户是否可用(1 可用,0 删除用户)
     */
    private boolean isEnabled = true;
    
    /**
     * 权限列表
     */
    @TableField(exist = false)
    Collection<? extends GrantedAuthority> authorities;
}

3.自定义UserDetailsService类:主要用于从数据库查询用户信息; 

1) 编写UserService接口
public interface UserService extends IService<User> { 
    /**
     * 根据用户名查询用户信息
     */
    User findUserByUserName(String userName);
}

2)编写UserService接口实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    /**
     * 根据用户名查询用户信息
     */
    @Override
    public User findUserByUserName(String userName) {
        //创建条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>(); 
        //用户名
        queryWrapper.eq("username",userName);
        //返回查询记录
        return baseMapper.selectOne(queryWrapper);
    }
}

3)自定义UserDetailsService类
import com.manong.entity.User;
import com.manong.service.UserService;
......
@Component
public class CustomerUserDetailsService implements UserDetailsService {
    @Resource
    private UserService userService;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //调用根据用户名查询用户信息的方法
        User user = userService.findUserByUserName(username);
        //如果对象为空,则认证失败
        if (user == null) {
            throw new UsernameNotFoundException("用户名或密码错误!"); 
        }
        return user;
    }
}

4.创建登录认证成功处理器:认证成功后需要返回JSON数据、菜单权限等;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.manong.entity.SysUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 
import org.springframework.stereotype.Component;
......
    
/**
 * 登录认证成功处理器类
*/
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //设置客户端的响应的内容类型
        response.setContentType("application/json;charset=UTF-8");
        
        //获取当登录用户信息
        SysUser user = (SysUser) authentication.getPrincipal();
        
        //消除循环引用
        String result = JSON.toJSONString(user, SerializerFeature.DisableCircularReferenceDetect);
        
        //获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }
}

5.创建登录认证失败处理器:认证失败后需要返回JSON数据给前端判断;

/**
 * 用户认证失败处理类
 */
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, 
                                        AuthenticationException exception) throws IOException, ServletException {
        //设置客户端响应编码格式
        response.setContentType("application/json;charset=UTF-8");
        //获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        String message = null;		//提示信息
        int code = 500;				//错误编码
        
        //判断异常类型
        if(exception instanceof AccountExpiredException){
            message = "账户过期,登录失败!";
        }else if(exception instanceof BadCredentialsException){
            message = "用户名或密码错误,登录失败!";
        }else if(exception instanceof CredentialsExpiredException){
            message = "密码过期,登录失败!";
        }else if(exception instanceof DisabledException){
            message = "账户被禁用,登录失败!";
        }else if(exception instanceof LockedException){
            message = "账户被锁,登录失败!";
        }else if(exception instanceof InternalAuthenticationServiceException){ 
            message = "账户不存在,登录失败!";
        }else{
            message = "登录失败!";
        }
        
        //将错误信息转换成JSON
        String result = JSON.toJSONString(Result.error().code(code).message(message));
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }
}

6. 创建匿名用户访问无权限时处理器:匿名用户访问时,需要返回JSON数据;

/**
 * 匿名用户访问资源处理器
 */
@Component
public class AnonymousAuthenticationHandler implements AuthenticationEntryPoint { 
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, 
                         AuthenticationException authException) throws IOException, ServletException {
        //设置客户端的响应的内容类型
        response.setContentType("application/json;charset=UTF-8");
        //获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        //消除循环引用
        String result = JSON.toJSONString(
            Result.error().code(600).message("匿名用户无权限访问!"), 
            SerializerFeature.DisableCircularReferenceDetect
        );
        
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }
}

7.创建认证用户访问无权限时处理器:无权限访问时,需要返回JSON数据;

/**
 * 认证用户访问无权限资源时处理器
 */
@Component
public class CustomerAccessDeniedHandler implements AccessDeniedHandler {
    
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, 
                       AccessDeniedException accessDeniedException) throws IOException, ServletException {
        
        //设置客户端的响应的内容类型
        response.setContentType("application/json;charset=UTF-8");
        //获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        //消除循环引用
        String result = JSON.toJSONString(
            Result.error().code(700).message("无权限访问,请联系管理员!"), 
            SerializerFeature.DisableCircularReferenceDetect
        );
        
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }
}

8.配置SpringSecurity配置类:把上面自定义的处理器交给SpringSecurity;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;
     @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private AnonymousAuthenticationHandler anonymousAuthenticationHandler;
    @Resource
    private CustomerAccessDeniedHandler customerAccessDeniedHandler;
    
     /**
     * 注入加密处理类
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    /**
     * 认证
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登录前进行过滤
        http.formLogin()
                .loginProcessingUrl("/api/user/login")
                // 设置登录验证成功或失败后的的跳转地址
                .successHandler(loginSuccessHandler).failureHandler(loginFailureHandler)
                // 禁用csrf防御机制
                .and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
                .and()
                .authorizeRequests()
                .antMatchers("/api/user/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(anonymousAuthenticationHandler)
                .accessDeniedHandler(customerAccessDeniedHandler)
                .and().cors();//开启跨域配置
    }
    
    /**
     * 配置认证处理器
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customerUserDetailsService).passwordEncoder(passwordEnco der());
    } 
}

3. token

4. 用户授权

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值