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");