上一篇文章中因为是第一次使用security这种机制。有些操做不太完备或者是为了实现某个功能走的弯路较多,这一章节是对上一章节的概括总结。固然也还有不完善地方。后期再应用中不断更新
安全机制html
<dependencies> <!-- 安全校验 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>
git clone https://github.com/spring-projects/spring-security.git
WebSecurityConfigurerAdapter 提供了默认安全校验机制的配置
查看源码:git
protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() //任何请求须要进行身份校验 .and() .formLogin() //提交表单验证方式 .and() .httpBasic(); }
为了改变其默认行为,咱们能够提供一个子类覆盖WebSecurityConfigurerAdapter的默认行为github
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .antMatchers("/students/**").hasRole("ADMIN") .and() .formLogin() .and() .httpBasic(); } }
进行web安全配置web
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() //受权请求 .antMatchers("/students/**").hasRole("ADMIN") //受权请求 .and() .formLogin() .loginPage("/login") //自定义登陆页面 .permitAll() //容许全部人访问该路由 .and() .csrf() .disable() //暂时禁用csrc不然没法提交 .httpBasic(); } }
添加/login跳转服务spring
@Controller public class IndexController { @GetMapping("/error") public String error() { return "redirect:/error_page.html"; } @GetMapping("/login") public String login(Model model, @RequestParam(value = "error", required = false) String error) { if (error != null) { model.addAttribute("error", "用户名或密码错误"); } return "forward:/login_page.html"; } }
提供登陆页面数据库
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陆页面</title> </head> <body> <h2>自定义登陆页面</h2> <hr> <form action="/login" method="POST" name="f"> 用户名<input type="text" name="username"/> <br> 密码 <input type="password" name="password"> <br> <input type="submit" value="登陆"> </form> </body> </html>
默认访问'/logout'即完成退出功能,默认security机制会进行以下操做安全
固然,咱们也能够自定义退出功能session
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .antMatchers("/students/**").hasRole("ADMIN") .and() .formLogin() .loginPage("/login") //自定义登陆页面 .permitAll() //容许全部人访问该路由 .and() .logout() //自定义登出操做 .logoutUrl("/logout") .logoutSuccessUrl("/login") .logoutSuccessHandler((req,resp,auth)->{ //登出成功处理函数 System.out.println("logout success"); resp.sendRedirect("/login?logout"); }) .invalidateHttpSession(true) .addLogoutHandler((req,resp,auth)->{ //登出处理函数 System.out.println("logout------"); }) //.deleteCookies("") .and() .csrf() .disable() //暂时禁用csrc不然没法提交 .httpBasic(); } }
重写用户服务app
/** * 用户认证服务 * */ @Bean @Override protected UserDetailsService userDetailsService() { //建立基于内存用户管理对象 InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); //自定义权限 Collection<GrantedAuthority> adminAuth = new ArrayList<>(); adminAuth.add(new SimpleGrantedAuthority("ADMIN")); //自定义用户 User u = new User("terry", "123321", true, true, true, true, adminAuth); manager.createUser(u); return manager; }
作法与基于内存相似,不过基于内存是本身建立用户对象,而基于jdbc须要从数据库中查询数据而后为身份验证提供数据。实际上验证操做仍是有security来完成,咱们无非是给security提供用户信息而已。maven
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .failureHandler((req,resp,authException)->{ System.out.println(authException.getMessage()); resp.sendRedirect("/login?error"); }) .loginPage("/login") //自定义登陆页面 .successHandler((req,resp,auth)->{ //获取登陆者信息 Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal != null && principal instanceof UserDetails) { UserDetails user = (UserDetails) principal; System.out.println("login success:"+user.getUsername()); //维护在session中 req.getSession().setAttribute("userDetail", user); resp.sendRedirect("/"); } }) .permitAll() //容许全部人访问该路由 .and() .logout() //自定义登出操做 .logoutUrl("/logout") .logoutSuccessUrl("/login") .logoutSuccessHandler((req,resp,auth)->{ //登出成功处理函数 System.out.println("logout success"); resp.sendRedirect("/login?logout"); }) .invalidateHttpSession(true) .addLogoutHandler((req,resp,auth)->{ //登出处理函数 System.out.println("logout------"); }) //.deleteCookies("") .and() .csrf() .disable() //暂时禁用csrc不然没法提交 .httpBasic(); } /** * 基于JDBC用户认证服务 * */ @Bean @Override protected UserDetailsService userDetailsService() { return new UserDetailsService() { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { UserDetails userDetails = null; try { User user = userMapper.findByUsername(name); if(user != null) { List<UserRole> urs = userRoleMapper.findByUserId(user.getId()); Collection<GrantedAuthority> authorities = new ArrayList<>(); for(UserRole ur : urs) { String roleName = ur.getRole().getName(); SimpleGrantedAuthority grant = new SimpleGrantedAuthority(roleName); authorities.add(grant); } //封装自定义UserDetails类 userDetails = new MyUserDetails(user, authorities); } else { throw new UsernameNotFoundException("该用户不存在!"); } } catch (Exception e) { e.printStackTrace(); } return userDetails; } }; } } /** * 自定义用户身份信息 * */ class MyUserDetails implements UserDetails { // 用户信息 private User user; // 用户角色 private Collection<? extends GrantedAuthority> authorities; public MyUserDetails(User user, Collection<? extends GrantedAuthority> authorities) { super(); this.user = user; this.authorities = authorities; } /** * */ private static final long serialVersionUID = 1L; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return this.user.getPassword(); } @Override public String getUsername() { return this.user.getUsername(); } @Override public boolean isAccountNonExpired() { return !this.user.getState().equals(User.STATE_ACCOUNTEXPIRED); } @Override public boolean isAccountNonLocked() { return !this.user.getState().equals(User.STATE_LOCK); } @Override public boolean isCredentialsNonExpired() { return !this.user.getState().equals(User.STATE_TOKENEXPIRED); } @Override public boolean isEnabled() { return !this.user.getState().equals(User.STATE_NORMAL); } }