Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。
Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。像所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求
官方文档参考
org.springframework.boot</groupId>
spring-boot-starter-security</artifactId>
</dependency>
server.port=8086
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hello")
public String hello(){
return "Hello SpringSecurity!";
}
}
当你看到这个登陆页面时,说明你在SpringBoot中整合SpringSecurity已经成功了
但是我们并没有在项目中设置用户名和密码 ,也没有写 /login ;但是别忘了我们引入了SpringSecurity, 如果我们没有进行SpringSecurity配置的话,它在启动时就会默认配置(源码截图如下)
默认用户名 user ,查看我们启动日志SpringSecurity还随机生成了一串密码:
输入用户名和密码:
我们成功访问到 /user/hello :
spring.security.user.name=zcc
spring.security.user.password=123
重启项目,输入我们自定义的用户名和密码,也成功访问到 /user/hello
自定义一个 Spring Security 的配置类,继承 WebSecurityConfigurerAdapter 类:
重写 configure(AuthenticationManagerBuilder auth) 方法,配置用户名,密码,角色
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();//不加密
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("zhangsan").password("123");
}
}
重启项目后,通过上面用户和密码也可成功访问到 /user/hello
通过上面自定义配置类也可以为用户配置角色及配置多用户 :
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() //开启在内存中定义用户
.withUser("zhangsan").password("123").roles("admin") //用户名 密码 角色
.and() //配置多个用户,用 and 相连
.withUser("zhangsan2").password("123").roles("user");
}
重写 configure(WebSecurity web) 来配置忽略掉的 URL 地址,一般是配置忽略静态文件 :
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
}
然后我们改造一下我们的 UserController 方便我们测试配置的用户角色 :
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hello")
public String hello(){
return "Hello SpringSecurity!";
}
@RequestMapping("/admin")
public String admin(){
return "你有admin角色";
}
@RequestMapping("/user")
public String user(){
return "你有user角色";
}
}
重写 configure(HttpSecurity http) 进行登陆配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护)
.antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问
.antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问
.and().formLogin();
}
重启项目,我们用拥有 admin 角色的用户: zhangsan 登陆访问 /admin/hello 和 /hello 都访问成功
访问 /user/hello 看到这个
表明他没有这个访问权限,同理用户: zhangsan2 ,也是不能访问 /admin/hello
但是如果做前后端分离,用postman测试,如果我们的请求方式不是 get 请求时,也会给我们报 403 :
然后我百度了一下,说的是从Spring Security 4.0开始,默认情况下会启用CSRF保护,以防止CSRF攻击应用程序,Spring Security CSRF会针对PATCH,POST,PUT和DELETE方法进行防护。
然后我们 禁用CSRF保护
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护)
.antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问
.antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问
.and().formLogin()
.and().csrf().disable() ; //禁用CSRF保护(支持跨域)
}
重启项目,用postman 登陆后就可以正常访问了
但是登陆成功后我们会发现给我们返回了 404 :
为什么会出现这种情况呢?肯定有的小伙伴会说我知道还用问你呀,那是我们从头到尾就没有哪个地方写过登陆成功或失败的返回,好了废话不多说上代码:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护)
.antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问
.antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问
.and().formLogin()
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("登陆成功!"));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("登陆失败!"));
out.flush();
out.close();
}
})
.and().csrf().disable(); //禁用CSRF保护
}
有人肯定又有话要说了 JDK1.8 的 Lambda 表达式 用起来不香吗,还用这个,马上安排:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护)
.antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问
.antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问
.and().formLogin()
.successHandler((httpServletRequest, httpServletResponse, authentication) -> {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("登陆成功!"));
out.flush();
out.close();
})
.failureHandler((httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("登陆失败!"));
out.flush();
out.close();
})
.and().csrf().disable(); //禁用CSRF保护
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护)
.antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问
.antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问
.and().formLogin()
.successHandler((httpServletRequest, httpServletResponse, authentication) -> {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("登陆成功!"));
out.flush();
out.close();
})
.failureHandler((httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("登陆失败!"));
out.flush();
out.close();
})
.and().logout()
.logoutSuccessHandler((httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString("注销成功!"));
out.flush();
out.close();
})
.and().csrf().disable(); //禁用CSRF保护
}
走起:
好了,到这里我们SpringBoot整合SpringSecurity的入门级(基于内存用户名和密码的登陆,登出)操作就完成了
本博客是博主一字一字手敲出来的 , 如果大家觉得我哪里有不对的地方,欢迎大家在评论区给我指出来