This commit is contained in:
xiangwb
2018-03-30 10:51:27 +08:00
parent 3cb286f557
commit d4063ad719
12 changed files with 167 additions and 143 deletions
@@ -1,7 +1,6 @@
package com.xwbing.util.captcha;
import com.xwbing.constant.CommonConstant;
import com.xwbing.util.CommonDataUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -9,6 +8,7 @@ import javax.imageio.ImageIO;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
@@ -33,10 +33,9 @@ public class CaptchaServlet extends HttpServlet {
CaptchaUtil tool = new CaptchaUtil();
StringBuffer code = new StringBuffer();
BufferedImage image = tool.genRandomCodeImage(code);
// HttpSession session = req.getSession();
// session.removeAttribute(CommonConstant.KEY_CAPTCHA);
// session.setAttribute(CommonConstant.KEY_CAPTCHA, code.toString());
CommonDataUtil.setToken(CommonConstant.KEY_CAPTCHA, code.toString());
HttpSession session = req.getSession();
session.removeAttribute(CommonConstant.KEY_CAPTCHA);
session.setAttribute(CommonConstant.KEY_CAPTCHA, code.toString());
// 将内存中的图片通过流形式输出到客户端
OutputStream out = res.getOutputStream();
ImageIO.write(image, "JPEG", out);
@@ -2,7 +2,7 @@
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/springboot2?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=
jdbc.password=xwbing
# 初始化大小,最小,最大
jdbc.initSize=1
jdbc.minIdle=3
@@ -3,7 +3,6 @@ package com.xwbing.configuration;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.xwbing.handler.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@@ -29,7 +28,7 @@ public class DispatcherServletConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截器1:登录判断
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
// registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
// registry.addInterceptor(new LoginInterceptor())
// .addPathPatterns("/**").excludePathPatterns("/user/login", "/servlet/captchaCode", "/swagger-ui.html");
//拦截器2...
@@ -108,25 +108,10 @@ public class SysUserControl {
@LogInfo("登录")
@ApiOperation(value = "登录", response = RestMessageVo.class)
@PostMapping("login")
public JSONObject login(HttpServletRequest request, @RequestParam String userName, @RequestParam String passWord, @RequestParam String checkCode) {
public JSONObject login(HttpServletRequest request, @RequestParam String userName, @RequestParam String passWord, @RequestParam String checkCode, boolean rememberMe) {
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(passWord)) {
return JsonResult.toJSONObj("用户名或密码不能为空");
}
if (StringUtils.isEmpty(checkCode)) {
return JsonResult.toJSONObj("请输入验证码");
}
RestMessage login = sysUserService.login(request, userName, passWord, checkCode);
return JsonResult.toJSONObj(login);
}
@LogInfo("登录")
@ApiOperation(value = "登录", response = RestMessageVo.class)
@PostMapping("login2")
public JSONObject login2(HttpServletRequest request, @RequestParam String userName, @RequestParam String passWord, @RequestParam String checkCode, boolean rememberMe) {
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(passWord)) {
return JsonResult.toJSONObj("用户名或密码不能为空");
}
SysUser user = sysUserService.getByUserName(userName);
Subject subject = SecurityUtils.getSubject();
String ip = IpUtil.getIpAddr(request);
UsernamePasswordCaptchaToken token = new UsernamePasswordCaptchaToken(userName, passWord.toCharArray(), rememberMe, ip, checkCode);
@@ -135,7 +120,7 @@ public class SysUserControl {
//保存登录信息
SysUserLoginInOut loginInOut = new SysUserLoginInOut();
loginInOut.setCreateTime(new Date());
loginInOut.setUserId(user.getId());
loginInOut.setUserId("");
loginInOut.setInoutType(CommonEnum.LoginInOutEnum.IN.getValue());
loginInOut.setIp(ip);
RestMessage save = loginInOutService.save(loginInOut);
@@ -150,14 +135,6 @@ public class SysUserControl {
@ApiOperation(value = "登出", response = RestMessageVo.class)
@GetMapping("logout")
public JSONObject logout(HttpServletRequest request) {
RestMessage logout = sysUserService.logout(request);
return JsonResult.toJSONObj(logout);
}
@LogInfo("登出")
@ApiOperation(value = "登出", response = RestMessageVo.class)
@GetMapping("logout2")
public JSONObject logout2(HttpServletRequest request) {
Subject subject = SecurityUtils.getSubject();
if (subject != null && subject.getPrincipals() != null) {
SysUser sysUser = (SysUser) subject.getPrincipals().getPrimaryPrincipal();
@@ -173,7 +150,7 @@ public class SysUserControl {
}
}
}
return JsonResult.toJSONObj(new Object(),"登出成功");
return JsonResult.toJSONObj(new Object(), "登出成功");
}
@LogInfo("修改密码")
@@ -3,6 +3,8 @@ package com.xwbing.handler;
import com.alibaba.fastjson.JSONObject;
import com.xwbing.exception.BusinessException;
import com.xwbing.util.JsonResult;
import com.xwbing.util.captcha.CaptchaException;
import org.apache.shiro.authc.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
@@ -50,11 +52,19 @@ public class GlobalExceptionHandler {
}
/**
* CompletableFuture完成结果或任务过程中出现的异常
* shiro登录认证
*
* @param ex
* @return
*/
@ExceptionHandler(value = AuthenticationException.class)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public JSONObject handlerAuthenticationException(AuthenticationException ex) {
logger.error(ex.getMessage());
return JsonResult.toJSONObj(ex.getMessage());
}
@ExceptionHandler(value = CompletionException.class)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
@@ -69,6 +79,20 @@ public class GlobalExceptionHandler {
return JsonResult.toJSONObj(errorMessages);
}
/**
* 验证码异常
*
* @param ex
* @return
*/
@ExceptionHandler(value = CaptchaException.class)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public JSONObject handlerCaptchaException(CaptchaException ex) {
logger.error(ex.getMessage());
return JsonResult.toJSONObj(ex.getMessage());
}
/**
* 表单检验(validator) 异常
*
@@ -1,70 +0,0 @@
package com.xwbing.handler;
import com.alibaba.fastjson.JSON;
import com.xwbing.configuration.DispatcherServletConfig;
import com.xwbing.constant.CommonConstant;
import com.xwbing.util.CommonDataUtil;
import com.xwbing.util.RestMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Set;
/**
* 说明: 登录拦截器
* 项目名称: boot-module-demo
* 创建时间: 2017/5/10 16:36
* 作者: xiangwb
*/
public class LoginInterceptor extends HandlerInterceptorAdapter {
private final Logger logger = LoggerFactory.getLogger(DispatcherServletConfig.class);
private static final Set<String> set = new HashSet<>();//拦截器白名单
static {
//映射到登录页面,不拦截
set.add("/");
//映射swagger文档
set.add("/doc");
//验证码
set.add("/captcha");
//swagger
set.add("/v2/api-docs");
set.add("/swagger-resources");
set.add("/configuration/ui");
set.add("/configuration/security");
//德鲁伊监控
set.add("/druid");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String servletPath = request.getServletPath();
if (!set.contains(servletPath) && !servletPath.contains("login") && !servletPath.contains("test")) {
// HttpSession session = request.getSession();
// if (session.getAttribute(CommonConstant.CURRENT_USER)!=null) {
// return true;
// }else {
// return false;
// }
if (CommonDataUtil.getToken(CommonConstant.CURRENT_USER) != null) {
return true;
} else {
logger.info("用户未登录");
OutputStream outputStream = response.getOutputStream();
RestMessage restMessage = new RestMessage();
restMessage.setMessage("请先登录");
outputStream.write(JSON.toJSONString(restMessage).getBytes("utf-8"));
outputStream.close();
//未登录,重定向到登录页面
// response.sendRedirect("/login.html");
return false;
}
}
return true;
}
}
@@ -0,0 +1,38 @@
package com.xwbing.shiro;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 项目名称: boot-module-demo
* 创建时间: 2018/3/29 15:28
* 作者: xiangwb
* 说明:
*/
public class FormAuthenticationCaptchaFilter extends FormAuthenticationFilter {
public static final String DEFAULT_CAPTCHA_PARAM = "captcha_code";
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
public String getCaptchaParam() {
return captchaParam;
}
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
}
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
String captcha = getCaptcha(request);
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
return new UsernamePasswordCaptchaToken(username, password.toCharArray(), rememberMe, host, captcha);
}
}
@@ -0,0 +1,41 @@
package com.xwbing.shiro;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
/**
* 项目名称: boot-module-demo
* 创建时间: 2018/3/29 16:29
* 作者: xiangwb
* 说明:
*/
public class MySessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "Authorization";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public MySessionManager() {
super();
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
//如果请求头中有 Authorization 则其值为sessionId
if (StringUtils.isNotEmpty(id)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
} else {
//否则按默认规则从cookie取sessionId
return super.getSessionId(request, response);
}
}
}
@@ -4,12 +4,9 @@ import com.xwbing.constant.CommonConstant;
import com.xwbing.domain.entity.sys.SysAuthority;
import com.xwbing.domain.entity.sys.SysRole;
import com.xwbing.domain.entity.sys.SysUser;
import com.xwbing.exception.BusinessException;
import com.xwbing.service.sys.SysRoleService;
import com.xwbing.service.sys.SysUserService;
import com.xwbing.util.CommonDataUtil;
import com.xwbing.util.captcha.CaptchaException;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
@@ -72,7 +69,7 @@ public class MyShiroRealm extends AuthorizingRealm {
}
/**
* 认证.登录
* 登录.认证
*
* @param authenticationToken
* @return
@@ -81,22 +78,21 @@ public class MyShiroRealm extends AuthorizingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordCaptchaToken captchaToken = (UsernamePasswordCaptchaToken) authenticationToken;
String captcha = captchaToken.getCaptcha();
String imgCode = (String) SecurityUtils.getSubject().getSession().getAttribute(CommonConstant.KEY_CAPTCHA);
// if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(imgCode)) {
// throw new AuthenticationException("验证码错误");
// }
SysUser user = sysUserService.getByUserName(captchaToken.getUsername());
if (user == null) {
throw new BusinessException("账号错误");
throw new AuthenticationException("账号或密码错误");
}
String sysPassWord = user.getPassword();
String salt = user.getSalt();
boolean flag = sysUserService.checkPassWord(String.valueOf(captchaToken.getPassword()), sysPassWord, salt);
if (!flag) {
throw new BusinessException("密码错误");
throw new AuthenticationException("账号或密码错误");
}
String captcha = captchaToken.getCaptcha();
String imgCode = (String) CommonDataUtil.getToken(CommonConstant.KEY_CAPTCHA);
if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(imgCode)) {
throw new CaptchaException("验证码错误");
}
return new SimpleAuthenticationInfo(user, sysPassWord,
ByteSource.Util.bytes(salt), getName());
return new SimpleAuthenticationInfo(user, sysPassWord, ByteSource.Util.bytes(salt), getName());
}
}
@@ -3,8 +3,10 @@ package com.xwbing.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -16,37 +18,43 @@ import java.util.Map;
* 说明: anon,authc
*/
@Configuration
@PropertySource("classpath:shiro.properties")
public class ShiroConfig {
@Value("${rememberMeCookieMaxAge}")
private Integer rememberMeCookieMaxAge;
@Value("${globalSessionTimeout}")
private Long globalSessionTimeout;
@Value("${sessionValidationInterval}")
private String sessionValidationInterval;
@Value("${sessionsCacheName}")
private String sessionsCacheName;
@Value("${sessionIdCookieName}")
private String sessionIdCookieName;
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
public ShiroFilterFactoryBean shirFilter() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//配置登录的url和登录成功的url
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setSecurityManager(securityManager());
//配置访问权限
Map<String, String> chains = new LinkedHashMap<>();
// 配置不会被拦截的链接 顺序判断
chains.put("/favicon.ico", "anon");
chains.put("/static/**", "anon");
//映射到登录页面,不拦截
chains.put("/","anon");
//映射swagger文档
chains.put("/doc","anon");
//验证码
chains.put("/captcha","anon");
//swagger
chains.put("/v2/api-docs","anon");
chains.put("/swagger-resources","anon");
chains.put("/configuration/ui","anon");
chains.put("/configuration/security","anon");
//德鲁伊监控
chains.put("/druid","anon");
chains.put("/**", "authc");
//配置登录的url和登录成功的url
shiroFilterFactoryBean.setLoginUrl("/user/login");
// shiroFilterFactoryBean.setSuccessUrl("/index");
// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
// chains.put("/favicon.ico", "anon");
// chains.put("/static/**", "anon");
// chains.put("/", "anon");
// chains.put("/doc", "anon");
// chains.put("/captcha", "anon");
// chains.put("/v2/api-docs", "anon");
// chains.put("/swagger-resources", "anon");
// chains.put("/configuration/ui", "anon");
// chains.put("/configuration/security", "anon");
// chains.put("/druid", "anon");
// chains.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(chains);
System.out.println("Shiro拦截器工厂类注入成功");
return shiroFilterFactoryBean;
}
@@ -16,6 +16,11 @@ public class UsernamePasswordCaptchaToken extends UsernamePasswordToken {
private static final long serialVersionUID = 6059396037971862504L;
private String captcha;
public UsernamePasswordCaptchaToken() {
super();
}
public UsernamePasswordCaptchaToken(String username, char[] password, boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
@@ -0,0 +1,7 @@
### s
rememberMeCookieMaxAge=604800
globalSessionTimeout=1800000
sessionValidationInterval=60000
sessionsCacheName=shiro-activeSessionCache
sessionIdCookieName=drore.session.ywjpjScenic.id
path=/