很重要的一点:登录页面的 url和登录按钮提交的 url 要一致。否则,是不会进入到UserDetailService 的loadUserByUsername 方法中的。
第一步:引入 security 到项目中
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
第二步:实现 自己的SecurityConfig类(名字随意),需要继承 WebSecurityConfigurerAdapter,
然后重写 configure(HttpSecurity hhtp)方法,该方法主要是配置 http 请求的拦截规则,
http.authorizeRequests().antMatchers(exclusivePaths).permitAll() 这句是指允许所有人访问exclusivePaths数组中的资源(静态资源、登录的 url)
anyRequest().authenticated()是指除了上一句过滤的请求之外的所有请求都需要认证才能访问
formLogin()是默认的登录表单页,如果不配置 loginPage(url),则使用 spring security 默认的登录页,如果配置了 loginPage()则使用自定义的登录页
defaultSuccessUrl()是指登录成功之后跳转的页面
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private static final String[] exclusivePaths = {"/main/login", "/login", "/css/**", "/js/**", "/fonts/**", "/favicon.ico"}; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers(exclusivePaths).permitAll() .anyRequest().authenticated() .and() .formLogin().loginPage("/main/login") .defaultSuccessUrl("/main/index"); } @Override @Bean public UserDetailsService userDetailsServiceBean() { return new MyUserDetailServiceImpl(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsServiceBean()); } }
第三步:实现 UserDetailService 接口,并重写loadUserByUsername方法
public class MyUserDetailServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { System.out.println("进来了。。。"); MyUser user = new MyUser("weichaolei", "15269887654"); return user; } }
上面代码中的 MyUser 类实现了 UserDetails 接口,并重写了各种方法,代码如下
public class MyUser implements UserDetails{ private String username; private String password; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public MyUser(String username, String password) { this.username = username; this.password = password; } }
第四步:controller 和 html页面,要注意/main/login既支持 get 请求又支持 post 请求
@Controller public class MainController { @RequestMapping("/main/login") public String customLogin() { return "/login"; } @RequestMapping("/main/index") public String index() { return "/index2"; } @RequestMapping("/login") public String login() { return "/index"; } }
登录表单的 action 方法也是/main/login,一定要一致。还有一个登录成功的跳转页面,如下。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>自定义登录页面</title> </head> <body> <div class="container"> <form th:action="@{/main/login}" method="post"> <label for="username">用户名</label> <input type="text" class="form-control" id="username" name="username" autofocus="autofocus"/> <br/> <label for="password">密码</label> <input type="password" class="form-control" id="password" name="password"/> <br/> <input type="submit" class="btn btn-default" value="登录"/> </form> </div> </body> </html>
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head> <title>首页</title> </head> <body> <h1>您来了</h1> </body> </html>