赞
踩
spring security
的依赖。<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
controller
进行测试。 @GetMapping("/security_hello")
@ResponseBody
public String hello(){
return "hello,security";
}
user
,密码会在log中出现。Using generated security password: 9b7cd16e-af9e-4804-a6a2-9303df66ace8
controller
,可以看到这里 * 输入上面的密码,进行login。@configuration
。@Configuration public class SecurityConfig { @Bean PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Bean UserDetailsService userDetailsService() { InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(); users.createUser(User.withUsername("finlay_admin") .password("123456") .roles("ADMIN") .build()); users.createUser(User.withUsername("finlay_dba") .password("123456") .roles("DBA") .build()); users.createUser(User.withUsername("finlay_super") .password("123456") .roles("ADMIN", "DBA") .build()); return users; } @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth -> auth.requestMatchers ("/**")//匹配所有/** url .hasRole("ADMIN")//定义/**访问所需要ADMIN的role .anyRequest()//设定任何访问都需要认证 .authenticated()//设定任何访问都需要认证 ) .csrf(csrf -> csrf.disable())//csrf跨域访问无效 Cross-Site Request Forgery .sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true)); return http.build(); }
finlay_dba
这个user只设定了DBA
的role
,login是无效的finlay_super
这个user只设定了DBA
的role
,login是无效的controller
@GetMapping("/admin/hello") @ResponseBody public String helloAdmin() { return "hello,admin"; } @GetMapping("/user/hello") @ResponseBody public String helloUser() { return "hello,user"; } @GetMapping("/db/hello") @ResponseBody public String helloDB() { return "hello,DBA"; } @GetMapping("/hello") @ResponseBody public String hello() { return "hello"; }
url
的访问权限。@Configuration public class SecurityConfig { @Bean PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Bean UserDetailsService userDetailsService() { InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(); users.createUser(User.withUsername("finlay_user") .password("123456") .roles("USER") .build()); users.createUser(User.withUsername("finlay_admin") .password("123456") .roles("ADMIN") .build()); users.createUser(User.withUsername("finlay_dba") .password("123456") .roles("DBA") .build()); users.createUser(User.withUsername("finlay_super") .password("123456") .roles("ADMIN", "DBA") .build()); return users; } @Bean SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity.authorizeHttpRequests( auth -> auth.requestMatchers("/admin/**")//匹配所有/** url .hasRole("ADMIN")//只能对于admin的role,才能访问 .requestMatchers("/user/**")//匹配/user/** .hasRole("USER")//只有对于user的role,才能访问 .requestMatchers("/db/**")//配置/db/** .hasRole("DBA")//只有对于dba的role,才能访问 .anyRequest() .authenticated()//设定任何访问都需要认证 ) .formLogin(form -> form.loginProcessingUrl("/login")//这里对于前后端分离,提供的非页面访问url .usernameParameter("username")//页面上form的用户名 .passwordParameter("password"))//页面上form的密码 .csrf(csrf -> csrf.disable())//csrf跨域访问无效 .sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true)); return httpSecurity.build(); } }
/db/hello
。chrome
浏览器的session
数据。logout
功能,所以每次login
成功之后,都不能消除login
情报,这时候可以在chrome
浏览器直接使用快捷键ctrl-shift-del
之后进行session情报的删除。这样能够进行测试。通常的情况是不用spring security
默认提供的页面,下面进行自定义认证页面。
SecurityConfig
,controller
以及html
中进行配置`
url
@Bean SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity.authorizeHttpRequests(auth -> auth.requestMatchers("/login*") .permitAll() .requestMatchers("/admin/**")//匹配所有/** url .hasRole("ADMIN")//只能对于admin的role,才能访问 .requestMatchers("/user/**")//匹配/user/** .hasRole("USER")//只有对于user的role,才能访问 .requestMatchers("/db/**")//配置/db/** .hasRole("DBA")//只有对于dba的role,才能访问 .anyRequest() .authenticated()//设定任何访问都需要认证 ) .formLogin(form -> form.loginPage("/loginPage") .loginProcessingUrl("/doLogin")//这里对于前后端分离,提供的非页面访问url .usernameParameter("uname")//页面上form的用户名 .passwordParameter("passwd") .successHandler(new SuccessHandler())//认证成功的处理 .failureHandler(new FailureHandler())//认证失败的处理 .defaultSuccessUrl("/index")//默认的认证之后的页面 .failureForwardUrl("/loginPasswordError"))//默认的密码失败之后的页面 .exceptionHandling(exceptionHandling -> exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler())) .csrf(csrf -> csrf.disable())//csrf跨域访问无效 .sessionManagement(session -> session.maximumSessions(-1).maxSessionsPreventsLogin(true)); return httpSecurity.build(); }
url
,进行permitAll
开放,因为对于认证画面,不需要进行认证。auth.requestMatchers("/login*")
.permitAll()
controller
和view
注意,仅限于前后端一体程序.formLogin(form -> form.loginPage("/loginPage")
url
注意前后端一体和前后端分离程序都会使用用这个url
,springboot不对这个url定义controller
.loginProcessingUrl("/doLogin")//这里对于前后端分离,提供的非页面访问url
input
进行设定,这里之后的html
会使用。.usernameParameter("uname")//页面上form的用户名
.passwordParameter("passwd")
doLogin
,通过这里给前端返回结果对这两个类详细说明。 .successHandler(new SuccessHandler())//认证成功的处理
.failureHandler(new FailureHandler())//认证失败的处理
loginPage
,那么认证成功后默认的url
就是这里successForwardUrl
的区别是,successForwardUrl
是post
请求,这里是get
请求.defaultSuccessUrl("/index")//默认的认证之后的页面
url
.failureForwardUrl("/loginPasswordError"))//默认的密码失败之后的页面
url
,之后对CustomizeAccessDeniedHandler
类进行说明。exceptionHandling(exceptionHandling ->
exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler()))
success handler
类进行定义,主要在前后端的程序中使用。//success handler private static class SuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication ) throws IOException { Object principal = authentication.getPrincipal(); httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter printWriter = httpServletResponse.getWriter(); httpServletResponse.setStatus(200); Map<String, Object> map = new HashMap<>(); map.put("status", 200); map.put("msg", principal); ObjectMapper om = new ObjectMapper(); printWriter.write(om.writeValueAsString(map)); printWriter.flush(); printWriter.close(); }
failure handler
类进行定义,主要在前后端的程序中使用。//failure handler private static class FailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException authenticationException ) throws IOException { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter printWriter = httpServletResponse.getWriter(); httpServletResponse.setStatus(401); Map<String, Object> map = new HashMap<>(); map.put("status", 401); if (authenticationException instanceof LockedException) { map.put("msg", "账户被锁定,登陆失败"); } else if (authenticationException instanceof BadCredentialsException) { map.put("msg", "账户输入错误,登陆失败"); } else { map.put("msg", "登陆失败"); } ObjectMapper om = new ObjectMapper(); printWriter.write(om.writeValueAsString(map)); printWriter.flush(); printWriter.close(); }
CustomizeAccessDeniedHandler
类进行定义,对没有权限等情况进行定义。比如,需要的role
是ADMIN
,但是认证结束后的role
确是DBA
。private static class CustomizeAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendRedirect("/loginNoPermissionError");
}
}
controller
层做出一个LoginController
注意,为了定义permitAll方便,统一采用
login`开头@Controller public class LoginController { @GetMapping("/loginPage") public String loginPage() { return "login"; } @GetMapping("/loginNoPermissionError") public String loginNoPermission() { return "no_permission_error"; } @GetMapping("/loginPasswordError") public String loginError(Model model) { model.addAttribute("message", "认证失败"); return "password_error"; } @PostMapping("/loginPasswordError") public String loginErrorPost(Model model) { model.addAttribute("message", "认证失败"); return "password_error"; } }
view
层的各个html
注意,前后端分离程序
login
的认证画面view
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org/" lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Security 用户自定义认证画面</title>
</head>
<body>
<h1>自定义用户登陆</h1>
<form th:action="@{/doLogin}" method="post">
用户名:<input type="text" name="uname"><br>
密码:<input type="text" name="passwd"><br>
<input type="submit" value="登陆">
</form>
</body>
</html>
view
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org/" lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Security 用户自定义-密码输入错误</title>
</head>
<body>
<h1>自定义用户登陆错误-用户密码输入错误"</h1>
</form>
</body>
</html>
view
,比如需要ADMIN
的role
,但是用户只有DBA
的role
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org/" lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Security 用户自定义-权限不足</title>
</head>
<body>
<h1>"用户自定义画面,权限不足"</h1>
</form>
</body>
</html>
DBA
用户访问http://localhost:8080/db/hello
USER
的role
用户登录,但是访问http://localhost:8080/db/hello
,需要DBA
的role
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。