Spring Security对Web安全性的支持大量地依赖于Servlet过滤器。这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理。 Spring Security提供有若干个过滤器,它们能够拦截Servlet请求,并将这些请求转给认证和访问决策管理器处理,从而增强安全性。
-
1.导入依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>
-
2.pojo+mapper+service
@Data @AllArgsConstructor @NoArgsConstructor public class Users { private Integer id; private String username; private String password; }
@Repository @Mapper public interface UserMapper extends BaseMapper<Users> { }
@Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { @Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //调用userMapper中的方法,根据用户名查询数据库 QueryWrapper<Users> wrapper = new QueryWrapper<>(); wrapper.eq("username",username);//相当于where username=? Users users = userMapper.selectOne(wrapper); //查出的结果 if (users==null){ throw new UsernameNotFoundException("用户名不存在"); } //角色授权时,需加上ROLE_ List<GrantedAuthority> authorities= AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale"); //从数据库返回的user对象中得到用户名和密码 return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),authorities); } }
-
3.security配置类
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsService") private UserDetailsService userDetailsService; //注入数据源 @Autowired private DataSource dataSource; //配置对象,操作数据库,建立Token @Bean public PersistentTokenRepository persistentTokenRepository(){ JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); //jdbcTokenRepository.setCreateTableOnStartup(true); 自动创建表,这里已经手动创建了 return jdbcTokenRepository; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // String password = passwordEncoder.encode("123456"); //对密码进行加密 // auth.inMemoryAuthentication().passwordEncoder(passwordEncoder).withUser("admin2").password(password).roles("admin"); auth.userDetailsService(userDetailsService).passwordEncoder(password()); } @Bean PasswordEncoder password(){ return new BCryptPasswordEncoder(); //密码解密 } @Override protected void configure(HttpSecurity http) throws Exception { //配置没有权限访问403跳转页面 http.exceptionHandling().accessDeniedPage("/toUnAuths"); //退出页面设置,退出的路径“/logOut”(前端需和这里一致),退出成功后通过“/toLogin”跳转到登录页 http.logout().logoutUrl("/logOut").logoutSuccessUrl("/toLogin").permitAll(); http.formLogin() //自定义自己编写的登录页面 .loginPage("/toLogin") //登录页面设置 .loginProcessingUrl("/user/login1") //登录访问路径,该路径可以自定义只需要与表单保持一致就行,表单信息会自动提交到security中 .defaultSuccessUrl("/toSuccess").permitAll() //登陆成功后,跳转路径 .and().authorizeRequests() .antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以无需认证访问 //1.hasAuthority当前登录用户,只有拥有admins权限才能访问这个路径,只支持单个权限设置 // .antMatchers("/test/index").hasAuthority("admins") //2.hasAnyAuthority当前登录用户,拥有admins或者manager权限均可访问这个路径 // .antMatchers("/test/index").hasAnyAuthority("admins,manager") //3.hasRole方法,授予角色 .antMatchers("/test/index").hasRole("sale") .anyRequest().authenticated() .and().rememberMe().tokenRepository(persistentTokenRepository()) .tokenValiditySeconds(600) //设置有效时长,单位秒 .userDetailsService(userDetailsService) .and().csrf().disable(); //关闭csrf防护 } }
-
4.控制类
@Controller public class securityTest { @GetMapping("/test/index") @ResponseBody public String index(){ return "hello index"; } @RequestMapping({"/","/user/login","/toLogin"}) public String toLogin(){ return "login"; } @RequestMapping("/toUnAuths") public String toUnAuths(){ return "unAuths"; } @RequestMapping("/test/update") @ResponseBody //@Secured({"ROLE_sale","ROLE_manager"}) //注解添加角色,具有该角色才能访问 //@PreAuthorize("hasAnyAuthority('admins')") //在执行方法前验证权限 @PostAuthorize("hasAnyAuthority('admins')") //在执行方法后验证权限 public String update(){ System.out.println("=======>update........"); return "hello update"; } @GetMapping("/toSuccess") public String toSuccess(){ return "success"; } }
-
5.前端页面
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form th:action="@{/user/login1}" th:method="post"> 用户名:<input type="text" th:name="username"><br> 密码: <input type="text" th:name="password"><br> <input type="checkbox" name="remember-me"> 自动登录 <input type="submit" th:value="login"> </form> </body> </html>
success.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>登陆成功</h2><br> <a href="/logOut">退出</a> </body> </html>