SpringSecurity的简单使用

SpringSecurity是基于Spring应用提供的声明式的安全保护性的框架,它可以在web请求级别的和方法调用级别处理身份和授权。

1.引入SpringSecurity

创建maven项目引入依赖:

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

 

2.UserDetailsService的使用

当登录时,需要对传来的的参数进行验证,检测传来的用户名及密码是否正确,这时候就需要用UserDetailsService验证用户名、密码和授权。

@Service
public class UserDetailServiceImpl  implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //根据用户名进行查询 查询不到则报错
        if (!"admin".equals(userName)){
            throw new UsernameNotFoundException("用户名错误");
        }

            //模拟从数据库中取出加密后的密码
        String password=passwordEncoder.encode("123456");

        //返回查询结果 返回的User是springsecurity的类,
        return new User(userName,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_abc"));
    }

实现UserDetailsService接口,根据用户名查出密码和权限等其他信息,封装成User类返回,若用户名和密码等信息和前端传来的信息一致,则登陆成功,否则失败。

3.WebSecurityConfigurerAdapter类参数设置

登录成功或者失败,我们都需要设置跳转页面或者给某个页面能否访问设置权限。这就需要WebSecurityConfigurerAdapter类进行参数设置,一些常用的设置参数如下:

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    @Bean
    public PasswordEncoder getPe(){
        return  new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //表单提交
        http.formLogin()
                //自定义入参:设置表单的参数名称
                .usernameParameter("userName")
                .passwordParameter("password")
                //自定义登陆页面 确定哪个页面是登陆页面
        .loginPage("/login.html")
                //自定义登录逻辑,必须和表单提交接口一样,执行自定义登录逻辑
        .loginProcessingUrl("/login")
                //登陆成功后跳转页面,必须为post请求
       .successForwardUrl("/toMain")
                //自定义的登录成功处理器
              //  .successHandler(new MySuccessUrlHandler("http://www.baidu.com"))
        //失败跳转登陆页面 post请求
        .failureForwardUrl("/toError");
        //授权 所有请求必须经过认证

        //设置不需要认证的页面
        http.authorizeRequests().antMatchers("/login.html").permitAll()
                .antMatchers("/error.html").permitAll()
                //基于权限认证 若有叫做“admin”的权限才可访问该页面
                //.antMatchers("/main1.html").hasAnyAuthority("admin")
                //基于角色认证
                .antMatchers("/main1.html").hasRole("abcd")
                //基于ip地址认证
                //.antMatchers().hasIpAddress("");
                //上述各种方法都是基于access
                //.antMatchers().access("hasRole('abc')")
                //设置除了上述页面外,其他页面的访问皆需权限认证
                .anyRequest().authenticated();
        http.csrf().disable();
        //自定义异常处理器
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    }

}

自定义的登录成功处理器如下,登陆成功后会执行该方法:

public class MySuccessUrlHandler implements AuthenticationSuccessHandler {
    private String url;

    public MySuccessUrlHandler(String url) {
        this.url = url;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
    httpServletResponse.sendRedirect(url);
    }

}

 

 自定义的异常处理器如下:

@Component
public class MyAccessDenisHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
        httpServletResponse.setHeader("Context-Type","application/json");
        PrintWriter printWriter=httpServletResponse.getWriter();
        printWriter.write("{\"msg\":\"权限不足\"}");
        printWriter.flush();
        printWriter.close();
    }
}

  

1.@Secured()的使用

该注解可使用在controller或service上,但controller指定了接口,一般用于controller上,该注解是判断是否具有角色的,参数以"ROLE_"开头,若条件不允许,则报500错误。

开启注解配置:@EnableGlobalMethodSecurity(securedEnabled = true)

 @Secured("ROLE_ab")

2.@PreAuthorize()和@PostAuthorize()的使用

该注解和@Secured()相同,只不过是使用access表达式判断,@PreAuthorize()是在执行操作前判断,@PostAuthorize()是在执行后判断,因此使用较少。

开启注解配置:@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)

 @PreAuthorize("hasRole('ROLE_ab')")

3.Remenber-me功能的实现

该功能将用户数据存储到数据源中,一段时间内不用登录进行访问。该功能需要配置数据库和数据库连接池,

 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

  在权限配置类中的configure()方法中对remmber-me功能进行设置:

//remenber me
     *持久化token
     * Security中,默认是使用PersistentTokenRepository的子类InMemoryTokenRepositoryImpl,将token放在内存中
     * 如果使用JdbcTokenRepositoryImpl,会创建表persistent_logins,将token持久化到数据库
http.rememberMe().tokenRepository(persistentTokenRepository) //设置超时时间 .tokenValiditySeconds(60) //设置自定义登录逻辑 .userDetailsService(userDetailService);

JdbcTokenRepositoryImpl设置如下:

@Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository=new JdbcTokenRepositoryImpl();
        //设置数据源
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表,第一次启动开启,以后注释掉
       //dbcTokenRepository.setCreateTableOnStartup(true);
       return  jdbcTokenRepository;

 登陆页面中的remember-me功能:

    记住<input type="checkbox" name="remember-me" value="true" ><br/>

 5.退出登录

//退出登录
        http.logout()
                //退出成功到的url
                .logoutSuccessUrl("/login.html")
                //自定义退出登录接口
                .logoutUrl("/mylogout");

  

 

posted @ 2021-01-31 03:55  第十八使徒  阅读(198)  评论(0)    收藏  举报