SpringSecurity-简单实现

三种用户认证方式

1. 配置文件

spring.security.user.name=admin
spring.security.user.password=admin

2. 配置类 

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //密码加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("admin");
        //配置用户名和密码认证
        auth.inMemoryAuthentication().withUser("admin").password(password).roles("admin");
    }
    
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        //获取PasswordEncoder
        return new BCryptPasswordEncoder();
    }
    
}

3. UserDetailsService实现类

  •  配置类:
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;
        
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
    }
    
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        // 获取PasswordEncoder
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login.html")//登录的页面
                .loginProcessingUrl("/user/login")//登录的请求路径
                .defaultSuccessUrl("/test/index").permitAll()//登录成功之后的路径
                .and().authorizeRequests()
                    //设置哪些路径可以直接访问,不需要访问
                    .antMatchers("/","/test/hello","/user/login").permitAll()
                .anyRequest().authenticated()
                .and().csrf().disable();//关闭crsf防护
    }
    
}
  •  实现类:
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //用户权限
        List<GrantedAuthority> auths =
                AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User("admin",
                new BCryptPasswordEncoder().encode("admin"), auths);
    }
}

四种角色控制方式

  •  hasAuthority():单个角色控制
  •  hasAnyAuthority():多个角色控制,符合其一即可
  •  hasRole():单个角色控制
  • hasAnyRole():多个角色控制,符合其一即可

设置403页面

  •  当用户没有角色权限时,页面会报错403

  •  配置类设置403报错页面

常用注解

  • @Secured
    • 判断是否具有角色权限,匹配的字符串需要添加前缀“ROLE_角色权限”
    • 首先在配置类或者启动类上添加注解@EnableGlobalMethodSecurity(securedEnable = true)
    @RequestMapping("secured")
    @ResponseBody
    @Secured({"ROLE_sale","ROLE_admin"})
    public String secured() {
        System.out.println("---secured---");
        return "hello secured";
    }
  • @PreAuthorize
    • 进入方法之前进行角色权限认证
    • 首先在配置类或者启动类上添加注解@EnableGlobalMethodSecurity(prePostEnabled = true)
    @RequestMapping("/preAuthorize")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_sale')")
    public String preAuthorize(){
        //没权限不进入方法
        System.out.println("---preAuthorize---");
        return "hello preAuthorize";
    }
  •  @PostAuthorize
    • 方法执行之后再判断用户的角色权限
    • 首先在配置类或者启动类上添加注解@EnableGlobalMethodSecurity(securedEnable = true)
    @RequestMapping("/postAuthorize")
    @ResponseBody
    @PostAuthorize("hasRole('ROLE_sale')")
    public String postAuthorize(){
        //先执行方法再判断权限
        System.out.println("---postAuthorize---");
        return "hello postAuthorize";
    }
  •  @PostFilter
    • 根据设定的条件将返回值过滤
    @RequestMapping("postFilter")
    @PreAuthorize("hasRole('ROLE_sale')")
    @PostFilter("filterObject.username == 'admin1'")
    @ResponseBody
    public List<Users> postFilter(){
        System.out.println("---postFilter---");
        ArrayList<Users> list = new ArrayList<>();
        list.add(new Users(1,"admin1","admin1"));
        list.add(new Users(2,"admin2","admin2"));
        System.out.println(list);
        return list;//只返回过滤条件的数据
    }
  •  PreFilter
    • 根据过滤条件将传入参数进行过滤
    @RequestMapping("preFilter")
    @PreAuthorize("hasRole('ROLE_sale')")
    @PreFilter("filterObject.username == 'admin1'")
    @ResponseBody
    public List<Users> preFilter(@RequestBody List<Users> list){
        System.out.println("---preFilter---");
        //只收到过滤条件的数据参数
        System.out.println(list);
        return list;
    }

退出操作

//退出操作
http.logout()
    .logoutUrl("/logOut")//退出的请求路径
    .logoutSuccessUrl("/test/hello").permitAll();//退出后跳转的请求页面

自动登录 

  •  页面勾选框name只能是remember-me,否则无法识别到勾选框
<input type="checkbox" name="remember-me">自动登录</input>
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private DataSource dataSource;//注入数据源
    
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        //获取自动登录的配置实现类
        JdbcTokenRepositoryImpl jdbcTokenRepository=new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动创建表persistent_logins
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
    }
    
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        // 获取PasswordEncoder
        return new BCryptPasswordEncoder();
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登录表单提交
        http.formLogin()
                .loginPage("/login.html")//登录的页面
                .loginProcessingUrl("/user/login")//登录的请求路径
                .defaultSuccessUrl("/success.html").permitAll()//登录成功之后的路径
                .and().authorizeRequests()
                //设置哪些路径可以直接访问,不需要访问
                .antMatchers("/", "/test/hello", "/user/login").permitAll()
                //当前登录用户,只有具有admins权限才可以访问这个路径
                //1 hasAuthority方法
                // .antMatchers("/test/index").hasAuthority("admins")
                //2 hasAnyAuthority方法
                // .antMatchers("/test/index").hasAnyAuthority("admins,manager")
                //3 hasRole方法   ROLE_sale
                .antMatchers("/test/index").hasRole("sale")
                .anyRequest().authenticated()
                .and().rememberMe()//自动登录设置
                    .tokenRepository(getPersistentTokenRepository())
                    .tokenValiditySeconds(60)//记住用户60秒
                    .userDetailsService(userDetailsService)
                .and().csrf().disable();//关闭crsf防护
        
        //403异常跳转页面
        http.exceptionHandling().accessDeniedPage("/unAuth.html");
        
        //退出操作
        http.logout()
                .logoutUrl("/logOut")//退出的请求路径
                .logoutSuccessUrl("/test/hello").permitAll();//退出后跳转的请求页面
    }
}

CSRF

1. 简单理解

  • 跨站请求伪造(Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。
  • 跟跨网站脚本(XSS)相比,XSS利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
  • web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
  • 从Spring Security 4.0 开始,默认情况下会启用CSRF 保护,以防止CSRF 攻击应用程序,Spring Security CSRF 会针对 PATCH,POST,PUT 和DELETE 方法进行防护。

2. 具体实现

  • 关闭csrf配置,默认开启
http.csrf().disable()
  • 登录页面添加隐藏域
<input type="hidden" 
    th:if="${_csrf}!=null" 
    th:name="${_csrf.parameterName}" 
    th:value="${_csrf.token}"/>

  • 收到请求时,从请求中提取 csrfToken,和保存的 csrfToken 做比较,进而判断当前请求是否合法。主要通过 CsrfFilter 过滤器来完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值