springoboot与springsecurity整合基础篇

本章节基础入门篇

话不多说开干

  1. 首先引入springsecurity的pom
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
  1. 首先你要创建SecurityConfig(名可随便取) 继承 WebSecurityConfigurerAdapter类,重写三个configure方法
    WebSecurityConfigurerAdapter是适配器类,在配置的时候需要我们自己写配置类去继承他,然后编写自己所特殊需要的配置
import com.helei.security.MyAccessDeniedHandler;
import com.helei.security.MyAuthenticationEntryPoint;
import com.helei.security.MyAuthenticationFailureHandler;
import com.helei.security.MyAuthenticationSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SecurityJwtConfig extends WebSecurityConfigurerAdapter {

    //成功返回
    @Resource
    MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    
    //失败返回控制器
    @Resource
    MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    
    //未登录时
    @Resource
    MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    
    //权限不足时
    @Resource
    MyAccessDeniedHandler myAccessDeniedHandler;
    
    //密码编码器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Resource
    private PasswordEncoder passwordEncoder;
    
    @Resource
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/test/a").permitAll()
                .anyRequest().authenticated()
                //授权
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .usernameParameter("name")
                .passwordParameter("pass")
                //登录成功
                .successHandler(myAuthenticationSuccessHandler)
                //登录失败
                .failureHandler(myAuthenticationFailureHandler)
                .and()
                .exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler)
                .authenticationEntryPoint(myAuthenticationEntryPoint);
        http.csrf().disable();
    }

    /**
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }
}

  1. 首先看PasswordEncoder 如果不需要加密可用NoOpPasswordEncoder(),但是一般数据库存的都是加密密码所以一般用BCryptPasswordEncoder()
 //密码编码器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/test/a").permitAll()
                .anyRequest().authenticated()
                //授权
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .usernameParameter("name")
                .passwordParameter("pass")
                //登录成功
                .successHandler(myAuthenticationSuccessHandler)
                //登录失败
                .failureHandler(myAuthenticationFailureHandler)
                .and()
                .exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler)
                .authenticationEntryPoint(myAuthenticationEntryPoint);
        http.csrf().disable();
    }
  1. 我们来看看这个configure,它可以配置一下放行url,权限,异常等
    antMatchers(" ").permitAll().anyRequest().authenticated()配置的路径可放行,其他需要验证
    .formLogin()可配置登录路径
    .usernameParameter() 配置登录账号参数
    .passwordParameter() 配置登录密码参数
    上面的配置说明登录路径为http://localhost/login?name=&pass=
    如果不配置usernameParameter()passwordParameter(),默认是usernamepassword
    关键地方来了,如果你是前后一起的那么用 成功.successForwardUrl(“”)跳转登录成功后路径,失败同理 .failureForwardUrl(),一般都是前后分离,所以不这里不细讲
    前后分离项目我们登录成功或者失败都需要返回json给前端所以我们需要自定义返回的值

登录成功是由AuthenticationSuccessHandler进行处理结果的

//处理登录成功返回
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter out = response.getWriter();
        out.write(new ObjectMapper().writeValueAsString(Resp.getNew().success("登录成功")));
        out.flush();
        out.close();
    }
}

失败处理控制器

//失败处理控制器
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter out = response.getWriter();
        if (exception instanceof AccountExpiredException) {
            //账号过期
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("账号过期")));
        } else if (exception instanceof BadCredentialsException) {
            //密码错误
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("密码错误")));
        } else if (exception instanceof CredentialsExpiredException) {
            //密码过期
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("密码过期")));
        } else if (exception instanceof DisabledException) {
            //账户不可用
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("账户不可用")));
        } else if (exception instanceof LockedException) {
            //账户锁定
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("账户锁定")));
        } else if (exception instanceof InternalAuthenticationServiceException) {
            //用户不存在
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("用户不存在")));
        } else {
            out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("其他错误")));
        }
        out.flush();
        out.close();
    }
}

没有登录访问

/**
 * 未登录访问无权限资源时异常
 */
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter out = response.getWriter();
        out.write(new ObjectMapper().writeValueAsString(Resp.getNew().success("未登录")));
        out.flush();
        out.close();
    }
}

权限不足

/**
 * 权限不足异常
 */
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter out = response.getWriter();
        out.write(new ObjectMapper().writeValueAsString(Resp.getNew().success("权限不足")));
        out.flush();
        out.close();
    }
}

我们需要从数据库读取账户密码,所以实现UserDetailsService,这里role现在定死了,有需要可从数据库查询

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    @Resource
    SecurityUserMapper securityUserMapper;

    //根据 账号查询用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //将来连接数据库根据账号查询用户信息
        //暂时采用模拟数据
        // UserDetails build = User.withUsername("admin").password("123").authorities("a").build();

        //数据库查询
        SecurityUserEntity securityUserEntity = securityUserMapper.selectOne(new QueryWrapper<SecurityUserEntity>()
                .eq("name", username));
        String role = "update,a";
        String[] roles = role.split(",");
        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (String s : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+s));
        }
        // UserDetails build = User.withUsername(username).password(securityUserEntity.getPassword()).roles("a").build();
        return new User(username, securityUserEntity.getPassword(), authorities);

    }

}

如要用到注解权限需加上

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)

securedEnabled 开启 @Secured
prePostEnabled 开启@PreAuthorize

实例

@RestController
@RequestMapping("test")
public class AppUserController {

    @GetMapping("/a")
    public String index(){
        return "security jwt";
    }

    @PostMapping("/role")
    @PreAuthorize("hasAnyAuthority('ROLE_a')")
    public String roleInfo(){
        return "需要获得ROLE_a权限,才可以访问";
    }


   // @PreAuthorize("hasAnyAuthority('kdream')")
    @PostMapping("/roles")
    @Secured("ROLE_a")
    public String rolekdream(){
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        System.out.println(new Gson().toJson(userDetails));
        return "需要获得kdream权限,才可以访问";
    }
}

下章中级篇https://blog.csdn.net/he_lei/article/details/115599592

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值