@Service public class UserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //此處根據用戶名在數據庫中查找,這裏再也不查找,直接返回一個org.springframework.security.core.userdetails.User對象(若是是自定義的User類,須要實現UserDetails接口) return new User(username,new BCryptPasswordEncoder().encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } }
@Configuration public class BrowserSecurity extends WebSecurityConfigurerAdapter { //引入自定義UserDetailsService @Autowired private UserService userService; //加密 @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //配置內存認證 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //設置UserDetailsService以及密碼規則 auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } }
自定義User類實現該接口,該接口主要有以下方法html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>自定義登陸頁面登陸</title> </head> <body> <form action="/login" method="post"> <div class="form"> <h3>帳戶登陸</h3> <input type="text" placeholder="用戶名" name="username" required="required" /></br> <input type="password" placeholder="密碼" name="password" required="required" /> <button type="submit">登陸</button> </div> </form> </body> </html>
總體配置以下:java
@Configuration public class BrowserSecurity extends WebSecurityConfigurerAdapter { //引入自定義UserDetailsService @Autowired private UserService userService; //加密 @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //配置內存認證 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //設置UserDetailsService以及密碼規則 auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } //配置HttpSecurity @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //受權配置 .antMatchers("/myLogin.html").permitAll().anyRequest().authenticated() .and() //表單配置 .formLogin().loginPage("/myLogin.html").loginProcessingUrl("/login") .and() //默認都會產生一個hiden標籤 裏面有安全相關的驗證 防止請求僞造 這邊咱們暫時不須要 可禁用掉 .csrf().disable(); } }
除了登陸頁面能夠直接訪問,其餘請求須要跳轉到登陸頁面完成認證後才能夠訪問web
總體配置以下:spring
@Configuration public class BrowserSecurity extends WebSecurityConfigurerAdapter { //引入自定義UserDetailsService @Autowired private UserService userService; //加密 @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //配置內存認證 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //設置UserDetailsService以及密碼規則 auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } //配置HttpSecurity @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //受權配置 .antMatchers("/myLogin.html").permitAll().anyRequest().authenticated() .and() //表單配置 .formLogin().loginPage("/myLogin.html").loginProcessingUrl("/login") .successHandler(new AuthenticationSuccessHandler() { //登陸成功返回一段json信息 @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { //Authentication authentication 包含用戶登陸信息 String name = authentication.getName(); response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); response.setStatus(200); Map<String,Object> map = new HashMap<>(); map.put("status",200); map.put("msg",name); ObjectMapper mapper = new ObjectMapper(); out.write(mapper.writeValueAsString(map)); out.flush(); out.close(); } }) .failureHandler(new AuthenticationFailureHandler() { //登陸失敗,根據相關異常返回失敗信息 @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); response.setStatus(401); Map<String,Object> map = new HashMap<>(); map.put("status",401); if(e instanceof LockedException){ map.put("msg","帳戶被鎖定"); }else if(e instanceof BadCredentialsException){ map.put("msg","帳戶名或密碼錯誤"); }else if(e instanceof DisabledException){ map.put("msg","帳戶被禁用"); }else if(e instanceof AccountExpiredException){ map.put("msg","帳戶已過時"); }else if(e instanceof CredentialsExpiredException){ map.put("msg","密碼已過時"); }else{ map.put("msg","登陸失敗"); } ObjectMapper mapper = new ObjectMapper(); out.write(mapper.writeValueAsString(map)); out.flush(); out.close(); } }) .and() //默認都會產生一個hiden標籤 裏面有安全相關的驗證 防止請求僞造 這邊咱們暫時不須要 可禁用掉 .csrf().disable(); } }
@Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(authentication)); } }
@Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { } }
@Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() // 表單登陸 .successHandler(authenticationSucessHandler) // 處理登陸成功 .failureHandler(authenticationFailureHandler) // 處理登陸失敗 }
登陸成功
數據庫
登陸失敗
json