SpringSecurity入门总结

SpringSecurity=Authentication + Authorization

先上图

流程简介说明

别人的

 

相关的类图

画画花了好大一会功夫,以上纯属个人理解

介绍一下配置

用常用需求为例

1、特简单的web项目,几个Controller,2,3个角色,或者临时项目

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password("123").roles("ADMIN")
                .and()
                .withUser("user")
                .password("123").roles("USER");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .csrf().disable();

    }
}

说明:登录地址与操作都是login

2、前后端不分离,身份认证从库中对比

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 修改相应的密码比对方式
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Autowired
    UserService userService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .csrf().disable();

    }
}

说明:重点就在UserService类,实现

security.core.userdetails.UserDetailsService中的loadUserByUsername方法,根据用户名查询用户的信息及权限返回UserDetails

用户类必须继承security.core.userdetails.UserDetails

3、前后端分离,身份认证从库中对比,登录从表单改为Json,有验证码或者通过手机验证码动态登录

登录改成Json

自定义Filter继承自UsernamePasswordAuthenticationFilter

其实只要修改这个地方即可。

验证码或者通过手机验证码动态登录

方法一、写在前面的登录转json的Filter中,从request中取得数据,对比,不对直接抛出异常

方法二、自定义类继承AbstractUserDetailsAuthenticationProvider   or   DaoAuthenticationProvider,重写认证和密码比对方法

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 修改相应的密码比对方式
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    UserService userService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
    }

    @Bean
    MyLoginFilter loginFilter() throws Exception {
        MyLoginFilter loginFilter = new MyLoginFilter();
        loginFilter.setAuthenticationSuccessHandler((req, resp, authentication) -> {
            Map<String,Object> map = new HashMap<>();
            map.put("user",authentication.getPrincipal());
            ResultUtil.responseJson(resp,ResultUtil.resultSuccess(map));
        });
        loginFilter.setAuthenticationFailureHandler((req, resp, failed) -> {
            String msg;
            if(failed instanceof LockedException){
                msg = "账户被锁定,请联系管理员!";
            }else if (failed instanceof BadCredentialsException){
                msg = "用户名或者密码输入错误,请重新输入!";
            }else if(failed instanceof DisabledException){
                msg = "账户被禁用,请联系管理员!";
            }else if (failed instanceof AccountExpiredException){
                msg = "账户过期,请联系管理员!";
            }else if (failed instanceof CredentialsExpiredException){
                msg = "密码过期,请联系管理员!";
            }else{
                msg = "other";
            }
            resp.setStatus(400);
            ResultUtil.responseJson(resp,ResultUtil.resultCode(400,msg));
        });
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        return loginFilter;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/test/user").hasRole("USER")
                .antMatchers("/test/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()

                .logout()
                .logoutSuccessHandler((req,resp,authentication) -> {
                    ResultUtil.responseJson(resp,ResultUtil.resultCode(200,"注销登录成功"));
                })
                .and().csrf().disable()
                .exceptionHandling().authenticationEntryPoint((req,resp,exception) -> {
            resp.setStatus(401);
            ResultUtil.responseJson(resp,ResultUtil.resultCode(401,"尚未登录,请登录"));
        });
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

授权

方式一

protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/user/**").hasAnyRole("ADMIN", "USER")
            .anyRequest().authenticated()
            .and()
            ...
}

方式二

启动注解

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@PreAuthorize("hasRole('USER')")
@GetMapping(value="/delete")
public HttpResult delete() {
    return HttpResult.ok("the delete service is called success.");
}

@PreAuthorize("#age>98")
@GetMapping(value="/getAge")
public HttpResult getAge(Integer age){
    return HttpResult.ok("the getAge service is called success.");
}
@PreAuthorize("hasRole('USER') and hasRole('ADMIN')")
@PreAuthorize("principal.username.equals('admin')")
@PreAuthorize("hasAuthority('sys:notesDevice:selectAll')")

其实就是表达式

用hasAuthority或者用hasRole,取决于UserDetails的

private Collection<? extends GrantedAuthority> authorities;

如果authorities,中的存的是角色,必须是ROLE_开头,可以使用hasRole,如果是具体的权限串用hasAuthority,其实二个内部实现逻辑一样

方式三

过滤注解,个人理解,PreAuthorize对这一个方法而言,要不拒绝要不通过,而PreFilter则是方法的部分数据通过或者拒绝,PreFilter在方法前,PostFilter在方法后

@PostFilter("filterObject.lastIndexOf('H')!=-1")
public List<String> testList() {
    //.....
    return list;
}

@PreFilter(filterTarget = "ids",value = "filterObject % 2 == 0")
@GetMapping("/filter")
public String filter(@RequestParam("ids") List<Integer> ids,@RequestParam("name") String name){
    return name+"_filter"+ids;
}

方法四

启用hasPermission,灵活设置

PermissionEvaluator 是为表达式 hasPermission 提供支持的。

config中添加

    @Bean
    public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler(){
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(new MyPermissionEvaluator());
        return handler;
    }
public class MyPermissionEvaluator implements PermissionEvaluator {
    /**
     * 注入Service
     */
    @Autowired
    private UserService userService;


    /**
     * 灵活设置
     *
     * @param authentication
     * @param targetDomainObject hasPermission第一个参数
     * @param permission 第二个参数
     * @return true允许、false拒绝
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        return false;
    }
}

@PreAuthorize("hasRole('ADMIN') and hasPermission('/user/info','sys:user:info')")

方法五

动态权限,下回分解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值