本文共 19724 字,大约阅读时间需要 65 分钟。
User.class:
package com.example.demo.model;import lombok.AllArgsConstructor;import lombok.Getter;import lombok.NoArgsConstructor;import lombok.Setter;import lombok.extern.slf4j.Slf4j;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList;import java.util.Collection;import java.util.List;@Setter@Getter@AllArgsConstructor@NoArgsConstructor@Slf4jpublic class User implements UserDetails{ private Integer id; private String username; private String password; private Listroles; // private String role; // private String status; // private boolean checkLockIsOrNot=true; public User(String username,String password){ this.username = username; this.password = password; } //不涉及用户角色,直接赋予管理员角色 @Override public Collection getAuthorities() { List auths = new ArrayList<>(); auths.add(new SimpleGrantedAuthority("ROLE_ADMIN"); return auths; } //账户是否过期 @Override public boolean isAccountNonExpired() { return true; } //账户是否锁定 @Override public boolean isAccountNonLocked() { return true; } //密码是否过期 @Override public boolean isCredentialsNonExpired() { return true; } //是否可用 @Override public boolean isEnabled() { return true; }}
MyUserDetailService.class:
package com.example.demo.service;import com.example.demo.exception.ValidateCodeException;import com.example.demo.mapper.LockUserMapper;import com.example.demo.model.LockUser;import com.example.demo.model.User;import com.example.demo.model.UserLoginAttempts;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import org.springframework.social.connect.web.HttpSessionSessionStrategy;import org.springframework.social.connect.web.SessionStrategy;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.util.ArrayList;import java.util.List;/** * Created by linziyu on 2019/2/9. * * */@Component("MyUserDetailService")@Slf4jpublic class MyUserDetailService implements UserDetailsService{ @Autowired private UserService userService; // @Autowired // private LockUserMapper lockUserMapper; // private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { // ListgrantedAuthorityList = new ArrayList<>(); // grantedAuthorityList.add(new GrantedAuthority() { // @Override // public String getAuthority() { // return "admin"; // } // }); User user = userService.findByUserName(s);//数据库查询 看用户是否存在 // ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); // HttpServletRequest request = servletRequestAttributes.getRequest(); // request.setAttribute("username",s); if (user == null){ throw new ValidateCodeException("用户不存在"); }// LockUser lockUser = lockUserMapper.findLockUserById(user.getId());// log.info("{}",lockUser);// if ( lockUser != null) { // // throw new LockedException("LOCK");// user.setCheckLockIsOrNot(false);// } return user; }}
BrowerSecurityConfig.class:
package com.example.demo.config;import com.example.demo.filter.ValidateCodeFilter;import com.example.demo.handle.UserAuthenticationAccessDeniedHandler;import com.example.demo.handle.UserLoginAuthenticationFailureHandler;import com.example.demo.handle.UserLoginAuthenticationSuccessHandler;import com.example.demo.handle.UserLogoutSuccessHandler;import com.example.demo.service.MyUserDetailService;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;import javax.annotation.Resource;import javax.sql.DataSource;/** * Created by linziyu on 2019/2/8. * *Spirng Security 核心配置类 * */@Configuration//标识为配置类@EnableWebSecurity//启动Spring Security的安全管理// @EnableGlobalMethodSecurity(securedEnabled = true)// @Slf4jpublic class BrowerSecurityConfig extends WebSecurityConfigurerAdapter { private final static BCryptPasswordEncoder ENCODER = new BCryptPasswordEncoder(); // @Resource(name = "dataSource") // DataSource dataSource; @Bean public PasswordEncoder passwordEncoder(){ //密码加密类 return new BCryptPasswordEncoder(); } @Bean public MyUserDetailService myUserDetailService(){ return new MyUserDetailService(); }// @Bean// public PersistentTokenRepository persistentTokenRepository() { // JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();// // 配置数据源// jdbcTokenRepository.setDataSource(dataSource);// // 第一次启动的时候自动建表(可以不用这句话,自己手动建表,源码中有语句的)// // jdbcTokenRepository.setCreateTableOnStartup(true);// return jdbcTokenRepository;// } @Autowired private UserLoginAuthenticationFailureHandler userLoginAuthenticationFailureHandler;//验证失败的处理类 @Autowired private UserLoginAuthenticationSuccessHandler userLoginAuthenticationSuccessHandler;//验证成功的处理类 // @Autowired // private UserLogoutSuccessHandler userLogoutSuccessHandler; // @Autowired // private UserAuthenticationAccessDeniedHandler userAuthenticationAccessDeniedHandler; @Override protected void configure(HttpSecurity http) throws Exception { // ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter(); // http // .headers().frameOptions().sameOrigin();//设置弹出层 // http // .authorizeRequests() // .and() // .rememberMe() // .tokenRepository(persistentTokenRepository()) // .userDetailsService(myUserDetailService());; http .authorizeRequests() // .antMatchers("/admin/**","/setUserAdmin","/setUser","/deleteUserById") // .access("hasRole('ROLE_ADMIN')")//只有管理员才能访问 .antMatchers("/home","/static/**","/getAllUser","/register_page", "/register","/checkNameIsExistOrNot","/code/image")//静态资源等不需要验证 .permitAll()//不需要身份认证 .anyRequest().authenticated();//其他路径必须验证身份 http .formLogin() .loginPage("/login_page")//登录页面,加载登录的html页面 .loginProcessingUrl("/login")//发送Ajax请求的路径 .usernameParameter("username")//请求验证参数 .passwordParameter("password")//请求验证参数 .failureHandler(userLoginAuthenticationFailureHandler)//验证失败处理 .successHandler(userLoginAuthenticationSuccessHandler)//验证成功处理 .permitAll();//登录页面无需设置验证 // .and() // .rememberMe() // .tokenRepository(persistentTokenRepository()) // // 失效时间 // .tokenValiditySeconds(3600) // .userDetailsService(myUserDetailService()); // http // .logout() // .logoutSuccessHandler(userLogoutSuccessHandler)//登出处理 // .permitAll() // .and() // .csrf().disable() // .exceptionHandling().accessDeniedHandler(userAuthenticationAccessDeniedHandler);//无权限时的处理 } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailService()).passwordEncoder(new PasswordEncoder() { @Override public String encode(CharSequence charSequence) { return ENCODER.encode(charSequence); } //密码匹配,看输入的密码经过加密与数据库中存放的是否一样 @Override public boolean matches(CharSequence charSequence, String s) { return ENCODER.matches(charSequence,s); } }); }}
UserLoginAuthenticationSuccessHandler.class:
package com.example.demo.handle;import com.example.demo.common.JsonData;import com.google.gson.Gson;import lombok.extern.slf4j.Slf4j;import org.springframework.security.core.Authentication;import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;import org.springframework.stereotype.Component;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * Created by linziyu on 2019/2/9. * * 用户认证成功处理类 */@Component("UserLoginAuthenticationSuccessHandler")@Slf4jpublic class UserLoginAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { JsonData jsonData = new JsonData(200,"认证OK"); String json = new Gson().toJson(jsonData); response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.write(json); out.flush(); out.close(); }}
UserLoginAuthenticationFailureHandler.class:
package com.example.demo.handle;import com.example.demo.common.DateUtil;import com.example.demo.common.JsonData;import com.example.demo.model.User;import com.example.demo.model.UserLoginAttempts;import com.example.demo.service.UserService;import com.google.gson.Gson;import lombok.extern.slf4j.Slf4j;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;import org.springframework.stereotype.Component;import javax.annotation.Resource;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * Created by linziyu on 2019/2/9. * * 用户认证失败处理类 */@Component("UserLoginAuthenticationFailureHandler")@Slf4jpublic class UserLoginAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { @Resource private UserService userService; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { // log.info("{}","认证失败"); // log.info("{}",exception.getMessage()); // String username = (String) request.getAttribute("username"); JsonData jsonData = null; if (exception.getMessage().equals("用户不存在")){ jsonData = new JsonData(402,"用户不存在"); } if(exception.getMessage().equals("Bad credentials")){ jsonData = new JsonData(403,"密码错误"); // String user_name =userService.findByUserNameAttemps(username); // if (user_name == null){ // String time = DateUtil.getTimeToString(); // UserLoginAttempts userLoginAttempts = new UserLoginAttempts(username,1,time); // userService.saveAttempts(userLoginAttempts); // } // if(userService.getAttempts(username) == 1){ // String time = DateUtil.getTimeToString(); // userService.setAttempts(username,time); // jsonData = new JsonData(403,"密码错误,你还有2次机会进行登录操作"); // } // else if(userService.getAttempts(username) == 3){ // User user = userService.findByUserName(username); // userService.LockUser(user.getId()); // jsonData = new JsonData(403,"最后一次尝试登陆失败,你已经被冻结了"); // } // else if (userService.getAttempts(username) ==2 ){ // String time = DateUtil.getTimeToString(); // userService.setAttempts(username,time); // jsonData = new JsonData(403,"密码错误,你还有1次机会进行登录操作"); // } } // if (exception.getMessage().equals("User account is locked")){ // jsonData = new JsonData(100,"LOCK"); // } String json = new Gson().toJson(jsonData);//包装成Json 发送的前台 response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.write(json); out.flush(); out.close(); }}
登录页面:
密码错误:
用户不存在:
核心在login.js:
/** * Created by linziyu on 2019/2/9. */// 登录处理layui.use(['form','layer','jquery'], function () { var form = layui.form; var $ = layui.jquery; form.on('submit(login)',function (data) { var username = $('#username').val(); var password = $('#password').val(); var remember = $('input:checkbox:checked').val(); var imageCode = $('#imgcode').val(); $.ajax({ url:"/login",//请求路径 data:{ "username": username,//字段和html页面的要对应 id和name一致 "password": password,//字段和html页面的要对应 // "remember-me":remember, // "imageCode": imageCode }, dataType:"json", type:'post', async:false, success:function (data) { if (data.code == 402){ layer.alert("用户名不存在",function () { window.location.href = "/login_page" }); } if (data.code == 403){ layer.alert(data.msg,function () { window.location.href = "/login_page" }); } // if (data.code == 100){ // layer.alert("该用户已经被冻结,请联系管理员进行解冻",function () { // window.location.href = "/login_page" // }); // } if(data.code == 200){ window.location.href = "/"; } // if (data.code == 101){ // layer.alert(data.msg,function () { // window.location.href = "/login_page" // }); // } } }); })});
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.springframework.security.web.authentication;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.security.authentication.AuthenticationServiceException;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import org.springframework.util.Assert;public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username"; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password"; private String usernameParameter = "username"; private String passwordParameter = "password"; private boolean postOnly = true; public UsernamePasswordAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if(this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } else { String username = this.obtainUsername(request); String password = this.obtainPassword(request); if(username == null) { username = ""; } if(password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } protected String obtainPassword(HttpServletRequest request) { return request.getParameter(this.passwordParameter); } protected String obtainUsername(HttpServletRequest request) { return request.getParameter(this.usernameParameter); } protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); } public void setUsernameParameter(String usernameParameter) { Assert.hasText(usernameParameter, "Username parameter must not be empty or null"); this.usernameParameter = usernameParameter; } public void setPasswordParameter(String passwordParameter) { Assert.hasText(passwordParameter, "Password parameter must not be empty or null"); this.passwordParameter = passwordParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getUsernameParameter() { return this.usernameParameter; } public final String getPasswordParameter() { return this.passwordParameter; }}
数据库操作就不啰嗦了,用的是Mybatis+Mysql组合,无非是CRUD了。
具体demo在我的github:
转载地址:http://bxcqb.baihongyu.com/