1.SpringSecurity保护RestAPI

Spring Security 是一款优秀的安全框架,使用少量的配置就可以对我们的Web应用进行防护;随着前端框架的成熟,前后端分离项目越来越多,所以我们介绍使用SpringSecurity保护RestAPI。

一.简易配置

1.在mavan中引入spring-boot-starter-security

  • 引入spring-boot-starter-security依赖

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

2.SpringSecurity配置概览

  • 使用@EnableWebSecurity激活SpringSecurity的web保护
  • 继承WebSecurityConfigurerAdapter覆盖原有web适配器
  • 覆写protected void configure(HttpSecurity http)覆盖默认访问配置
  • 覆写public void configure(AuthenticationManagerBuilder web)自定义我们自己的用户数据源
  • 提供BCryptPasswordEncoder密码加密处理器
  • 初步配置如下:
    @EnableWebSecurity
    public class SimpleSecurityJavaConfig extends WebSecurityConfigurerAdapter {
    	@Override
    	public void configure(AuthenticationManagerBuilder web) throws Exception {
    		//使用内存管理器提供用户信息
    		web.inMemoryAuthentication()
    				.withUser("admin").password(encoder().encode("adminPass")).roles("ADMIN")
    				.and()
    				.withUser("user").password(encoder().encode("userPass")).roles("USER");
    	}
    
    	@Override
    	protected void configure(HttpSecurity http) throws Exception {
    		http.csrf().disable()//关闭csrf认证
    				.authorizeRequests()//配置请求接口权限开始
    				.antMatchers("/api/foos/**").authenticated()//foos下接口进行了权限认证后就可以访问了
    				.antMatchers("/api/admin/**").hasRole("ADMIN")//此接口需要拥有ADMIN权限的用户才能访问
    				.and()//连接符
    				.formLogin();//使用表单类型提交鉴权
    	}
    	@Bean
    	public PasswordEncoder encoder() {
    		return new BCryptPasswordEncoder();
    	}
    }
    

3.验证上述配置

  • 创建controller接口

    @Controller
    @RequestMapping(value = "/api/admin")
    public class AdminController {
    
    	@RequestMapping(value = "/hi", method = RequestMethod.GET)
    	@ResponseBody
    	public String hi() {
    		return "hey guys!";
    	}
    }
    
    @Controller
    @RequestMapping(value = "/api/foos")
    public class FooController {
    
    	@RequestMapping(method = RequestMethod.GET)
    	@ResponseBody
    	public List<Foo> findAll() {
    		return Lists.newArrayList(new Foo(randomAlphabetic(6)));
    	}
    }
    
  • 启动访问,此时我们访问被保护的API接口会跳转到SpringSecurity内置提供的页面http://localhost:8080/login页面

  • 我们输入账号密码后就可以正常访问,http://localhost:8080/api/foos,返回

    [{"id":0,"name":"rUNomg"}]
    
  • 但是,当我们用user账户去访问admin账户的http://localhost:8080/api/admin/hi就会返回权限不足,如下提示

    Whitelabel Error Page
    This application has no explicit mapping for /error, so you are seeing this as a fallback.
    
    Mon Nov 18 16:49:30 CST 2019
    There was an unexpected error (type=Forbidden, status=403).
    Forbidden
    

二.自定义配置

1.添加统一的错误处理

  • 上述出现的问题,1.访问任何页面将调到security自定义的登陆页面。2.没有访问错误做出统一的响应。3.没有对成功,失败,退出做出响应

  • 定义统一的错误处理,解决无登录访问,权限不够返回,鉴权失败等的统一处理,配置如下

     .exceptionHandling()
    .authenticationEntryPoint(restAuthenticationEntryPoint)//统一的错误处理
    
  • 具体实现,实现AuthenticationEntryPoint类,当鉴权失败后,就会调用commence返回401状态码

    @Component
    public final class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
        @Override
        public void commence(
            final HttpServletRequest request, 
            final HttpServletResponse response, 
            final AuthenticationException authException) throws IOException {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
        }
    }
    

2.添加登陆成功处理

  • 添加登陆成功后处理器

    .formLogin()
    .successHandler(mySuccessHandler)
    
  • 具体实现,自定义类实现AuthenticationSuccessHandler,重写onAuthenticationSuccess方法,执行登陆成功逻辑

    @Component
    public class MySavedRequestAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    	@Autowired
    	private ObjectMapper objectMapper;
    	@Override
    	public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException, ServletException {
    		//将账户信息返回
    		response.getWriter().write(objectMapper.writeValueAsString(authentication));
    	}
    }
    

3.添加登陆失败处理

  • 添加登陆失败处理器

    .formLogin()
    .failureHandler(myFailureHandler)//登陆失败处理
    
  • 具体实现,自定义失败处理类实现AuthenticationFailureHandler,重写onAuthenticationFailure方法,执行登陆失败逻辑

    @Component
    public class MyAuthenticationFailureHandler  implements AuthenticationFailureHandler {
    	@Autowired
    	private ObjectMapper objectMapper;
    	@Override
    	public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
    		//登陆失败将错误信息返回
    		httpServletResponse.getWriter().write(objectMapper.writeValueAsString(e.getMessage()));
    	}
    }
    

4.添加退出成功处理

  • 添加退出成功处理器

    .logout().logoutSuccessHandler(logoutSuccessHandler);//退出成功处理
    
  • 具体实现,自定义退出成功处理类实现LogoutSuccessHandler,重写onLogoutSuccess方法,执行退出后逻辑

    @Component
    public class MySimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {
    	@Autowired
    	private ObjectMapper objectMapper;
    	@Override
    	public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
    		//将账户信息返回
    		httpServletResponse.getWriter().write(objectMapper.writeValueAsString("logout success: "+authentication));
    	}
    }
    

5.自定义登陆账号密码key值

  • 系统默认账号密码

     this.usernameParameter("username");
     this.passwordParameter("password");
    
  • 我们可以通过如下配置来覆盖默认

    .formLogin()//使用表单类型提交鉴权
    .usernameParameter("user-name")
    .passwordParameter("pass-word")
    

6.配置类总览

  • 经过上述步骤,我们看一下我们的配置类

      @Override
    	protected void configure(HttpSecurity http) throws Exception {
    		http.csrf().disable()//关闭csrf认证
    				.exceptionHandling()
    				.authenticationEntryPoint(restAuthenticationEntryPoint)//统一的错误处理
    				.and()
    				.authorizeRequests()
    				.antMatchers("/api/foos/**").authenticated()//foos下接口进行了权限认证后就可以访问了
    				.antMatchers("/api/admin/**").hasRole("ADMIN")//此接口需要拥有ADMIN权限的用户才能访问
    				.anyRequest().authenticated()//除登陆,登出以及上述外所有请求都将拦截
    				.and()//连接符
    				.formLogin()//使用表单类型提交鉴权
    				//.usernameParameter("user-name")
    				//.passwordParameter("pass-word")
    				.successHandler(mySuccessHandler)//登陆成功处理
    				.failureHandler(myFailureHandler)//登陆失败处理
    				.and()
    				.logout().logoutSuccessHandler(logoutSuccessHandler);//退出成功处理
    	}
    

7.验证

  • SpringSecurity表单登陆默认的访问路径为localhost:8080/login,退出路径localhost:8080/logout
  • 未授权直接访问,返回401错误
  • 登陆成功返回,用户信息

三.结语

1.总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值