SpringSecurity

本文详细介绍SpringSecurity的使用,包括依赖配置、用户名密码手动配置、HTTP安全配置、方法安全、基于数据库认证等关键步骤。

SpringSecurity

springsecurity只需要添加一个依赖就可以保护所有的接口。

手动配置用户名和密码

  1. 配置文件中配置
	spring.security.user.name=admin
	spring.security.user.password=123456   
	spring.security.user.roles=admin

注释要另起一行;配置项目后面不要有空格。

  1. Java代码中配置
    新建一个config包,创建SecurityConfig类,继承WebSecurityConfigurerAdapter,重写configure方法。
 @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.inMemoryAuthentication()
               .withUser("admin").password("123").roles("admin")
               .and()
               .withUser("hurui").password("456").roles("user");
   }

这个方法从springboot5以后就不行了,因为密码要加密。在代码之前添加一个passwordEncoder()方法。
要用Bean注入

	@Bean
	PasswordEncoder passwordEncoder(){
        //  已经不用了
        return NoOpPasswordEncoder.getInstance();
    }

SpringSecurity中httpSecurity配置

作用:配置拦截规则

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()    // 开启配置
	     .antMatchers("/admin/**") // 选择路径规则  =>  /admin/**  只有admin能访问
	     .hasRole("admin")   //  需要的角色
	     .antMatchers("/user/**").hasAnyRole("admin","user")
	     .anyRequest().authenticated()   // 剩下的路径,登录之后才能访问
	     .and()
	     .formLogin()    //  登录信息
	     .loginProcessingUrl("/doLogin")     // 处理登录请求的地址
	     .loginPage("/login")    //  登录页面    =>  前后端分离不配
	     .usernameParameter("user")  //  将请求字段中默认的username改为user,名字上的区别
	                             //  ?username='***' => ?user='***'
	     .passwordParameter("pwd")
	     //  successHandler登录成功返回的信息,一般用在前后端分离的项目,返回一个json
	     //  successForwardUrl()登录成功后跳转的url,
	     .successHandler(new AuthenticationSuccessHandler() {
	         @Override
	         public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
	             Authentication authentication) throws IOException, ServletException {
	             //  authentication保存了登录成功的信息
	             resp.setContentType("application/json;charset=utf-8");
	             PrintWriter out = resp.getWriter();
	             Map<String,Object> map = new HashMap<>();
	             map.put("status",200);
	             map.put("msg",authentication.getPrincipal());
	             out.write(new ObjectMapper().writeValueAsString(map));
	             out.flush();
	             out.close();
	         }
	     })
	     .failureHandler(new AuthenticationFailureHandler() {
	         @Override
	         public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
	             AuthenticationException e) throws IOException, ServletException {
	             resp.setContentType("application/json;charset=utf-8");
	             PrintWriter out = resp.getWriter();
	             Map<String,Object> map = new HashMap<>();
	             map.put("status",500);
	             if (e instanceof LockedException) {
	                 map.put("msg","账户被锁定,登录失败");
	             } else if (e instanceof BadCredentialsException){
	                 map.put("msg","账户密码错误!");
	             } else if (e instanceof DisabledException) {
	                 map.put("msg","账户被禁用!");
	             } else if (e instanceof AccountExpiredException) {
	                 map.put("msg","账户过期!");
	             } else if (e instanceof CredentialsExpiredException) {
	                 map.put("msg","密码过期!");
	             } else {
	                 map.put("msg","登录失败!");
	             }
	             out.write(new ObjectMapper().writeValueAsString(map));
	             out.flush();
	             out.close();
	         }
	     })
	     .permitAll()    //  和登录相关的可以直接访问
	     .and()
	     .csrf().disable();  //  关闭csrf
    }

多个HttpSecurity配置

@Configuration
public class MultiHttpSecurityConfig {

    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("111").roles("admin")
                .and()
                .withUser("hurui").password("222").roles("user");
    }


    //  静态内部类配置不同的securityConfig类,Order配置优先级
    @Configuration
    @Order(1)
    public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter{
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasRole("admin");
        }
    }

    @Configuration
    public static class OtherSecurityConfig extends WebSecurityConfigurerAdapter{
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated()
               .and()
               .formLogin()
               .loginProcessingUrl("/doLogin")
               .permitAll()
               .and()
               .csrf()
               .disable();
        }
    }
}

密码加密

Spring boot自带了一个密码加密方法:BCryptPasswordEncode(),在之前的加密方法中return 这个方法就可以了。

方法安全

在方法上加注解确保方法的安全性。

  1. 在config配置类(springsecu配置类)上加注解
    @EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
    加上注解后就是有的方法是只有特定的角色才能访问。
    加上一个service层。
@Service
public class MethodService {

    @PreAuthorize("hasRole('admin')")
    public String admin(){
        return "admin can have access";
    }

    @Secured("ROLB_user")
    public String user() {
        return "user can have access";
    }

    @PreAuthorize("hasAnyRole('admin','user')")
    public String hello(){
        return "everyone can have access";
    }
}

在controller中加入相应的方法。

	@GetMapping("/hi1")
    public String hello1(){
        return methodService.admin();
    }

    @GetMapping("/hi2")
    public String hello2(){
        return methodService.user();
    }
    @GetMapping("/hi3")
    public String hello3(){
        return methodService.hello();
    }

admin角色登录之后,可以访问所有的url,但是在访问/hi2时会返回一个403,因为user()方法被限制了。

基于数据库认证

创建数据库User、Role、User-Role表。
编写实体类User和Role。

使用数据库作为SpringSecurity的用户时,用户类(user)要实现UserDetails接口。

  @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLB_" + role.getName()));
        }
        return authorities;
    }

注意角色默认有前缀ROLB_,如果数据中的字段已经有前缀了就不用加前缀的拼接。

使用数据库作为SpringSecurity的用户时,服务类(userService)要实现UserDetailsService接口。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值