单点登录接口和无条件登录接口优化改进,并在调用登录时统一增加登录成功和失败事件,方便返回登录信息。

This commit is contained in:
thinkgem
2020-09-20 09:49:22 +08:00
parent f3bb96d719
commit bbb37722d6
5 changed files with 101 additions and 74 deletions

View File

@@ -3,44 +3,34 @@
*/
package com.jeesite.common.shiro.filter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import com.jeesite.common.lang.ExceptionUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.realm.CasAuthorizingRealm;
import com.jeesite.common.shiro.realm.LoginInfo;
/**
* CAS过滤器
* @author ThinkGem
* @version 2018-7-11
* @version 2020-9-19
*/
@SuppressWarnings("deprecation")
public class CasAuthenticationFilter extends org.apache.shiro.cas.CasFilter {
private CasAuthorizingRealm authorizingRealm; // 安全认证类
/**
* 登录成功调用事件
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
// 登录成功后初始化授权信息并处理登录后的操作
authorizingRealm.onLoginSuccess((LoginInfo)subject.getPrincipal(), (HttpServletRequest)request);
// AJAX不支持Redirect改用Forward
request.getRequestDispatcher(getSuccessUrl()).forward(request, response);
return false;
return FormAuthenticationFilter.onLoginSuccess((HttpServletRequest)request, (HttpServletResponse)response);
}
/**
@@ -59,15 +49,15 @@ public class CasAuthenticationFilter extends org.apache.shiro.cas.CasFilter {
return false;
} else {
try {
if (ae != null && StringUtils.startsWith(ae.getMessage(), "msg:")){
String message = ExceptionUtils.getExceptionMessage(ae);
if (StringUtils.isNotBlank(message)){
request.setAttribute("exception", ae);
request.setAttribute("message", message);
request.getRequestDispatcher("/error/403").forward(request, response);
}else{
WebUtils.issueRedirect(request, response, getLoginUrl());
}
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
} catch (Exception e) {
e.printStackTrace();
}
return false;
@@ -75,7 +65,7 @@ public class CasAuthenticationFilter extends org.apache.shiro.cas.CasFilter {
}
public void setAuthorizingRealm(CasAuthorizingRealm authorizingRealm) {
this.authorizingRealm = authorizingRealm;
}
}

View File

@@ -34,7 +34,6 @@ import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.network.IpUtils;
import com.jeesite.common.shiro.authc.FormToken;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.web.CookieUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.Log;
@@ -45,20 +44,20 @@ import com.jeesite.modules.sys.utils.UserUtils;
/**
* 表单验证(包含验证码)过滤类
* @author ThinkGem
* @version 2020-4-13
* @version 2020-9-19
*/
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
public static final String CAPTCHA_PARAM = "validCode"; // 验证码
public static final String MESSAGE_PARAM = "message"; // 登录返回消息
public static final String REMEMBER_USERCODE_PARAM = "rememberUserCode"; // 记住用户名
public static final String EXCEPTION_ATTRIBUTE_NAME = "exception"; // 异常类属性名
public static final String CAPTCHA_PARAM = "validCode"; // 验证码
public static final String MESSAGE_PARAM = "message"; // 登录返回消息
public static final String REMEMBER_USERCODE_PARAM = "rememberUserCode"; // 记住用户名
public static final String EXCEPTION_ATTRIBUTE_NAME = "exception"; // 异常类属性名
private static final Logger logger = LoggerFactory.getLogger(FormAuthenticationFilter.class);
private BaseAuthorizingRealm authorizingRealm; // 安全认证类
private static FormAuthenticationFilter instance;
private Cookie rememberUserCodeCookie; // 记住用户名Cookie
private BaseAuthorizingRealm authorizingRealm;
private Cookie rememberUserCodeCookie; // 记住用户名Cookie
/**
* 构造方法
@@ -68,8 +67,16 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
rememberUserCodeCookie = new SimpleCookie(REMEMBER_USERCODE_PARAM);
rememberUserCodeCookie.setHttpOnly(true);
rememberUserCodeCookie.setMaxAge(Cookie.ONE_YEAR);
instance = this;
}
/**
* 创建登录授权令牌
*/
public static FormToken newToken(HttpServletRequest request, HttpServletResponse response) {
return (FormToken)instance.createToken(request, response);
}
/**
* 创建登录授权令牌
*/
@@ -100,7 +107,7 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
logger.info("登录账号为空或解码错误.");
}
}
// 登录成功后,判断是否需要记住用户名
// 登录判断是否需要记住用户名
if (WebUtils.isTrue(request, REMEMBER_USERCODE_PARAM)) {
rememberUserCodeCookie.setValue(EncodeUtils.encodeUrl(EncodeUtils.xssFilter(username)));
rememberUserCodeCookie.saveTo((HttpServletRequest)request, (HttpServletResponse)response);
@@ -241,30 +248,51 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
return super.executeLogin(request, response);
}
/**
* 登录成功调用事件(静态方便其他位置调用)
*/
public static boolean onLoginSuccess(HttpServletRequest request, HttpServletResponse response) {
try {
return instance.onLoginSuccess(null, null, request, response);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 登录成功调用事件
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
// 登录成功后初始化授权信息并处理登录后的操作
authorizingRealm.onLoginSuccess((LoginInfo)subject.getPrincipal(), (HttpServletRequest) request);
authorizingRealm.onLoginSuccess(UserUtils.getLoginInfo(), (HttpServletRequest)request);
// AJAX不支持Redirect改用Forward
request.getRequestDispatcher(getSuccessUrl()).forward(request, response);
try {
request.getRequestDispatcher(getSuccessUrl()).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 登录失败调用事件(静态方便其他位置调用)
*/
public static boolean onLoginFailure(AuthenticationException e, HttpServletRequest request, HttpServletResponse response) {
return instance.onLoginFailure(null, e, request, response);
}
/**
* 登录失败调用事件
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
String message = StringUtils.EMPTY;
if (e instanceof IncorrectCredentialsException || e instanceof UnknownAccountException) {
message = Global.getText("sys.login.failure");
} else if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")) {
if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")) {
message = StringUtils.replace(e.getMessage(), "msg:", "");
} else if (e instanceof IncorrectCredentialsException || e instanceof UnknownAccountException) {
message = Global.getText("sys.login.failure");
} else {
message = Global.getText("sys.login.error");
logger.error(message, e); // 输出到日志文件
@@ -272,20 +300,20 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
request.setAttribute(EXCEPTION_ATTRIBUTE_NAME, e);
request.setAttribute(MESSAGE_PARAM, message);
// 登录操作如果是Ajax操作直接返回登录信息字符串。
if (ServletUtils.isAjaxRequest(((HttpServletRequest) request))){
Map<String, Object> data = getLoginFailureData(((HttpServletRequest) request), ((HttpServletResponse) response));
ServletUtils.renderResult(((HttpServletResponse) response), Global.TRUE, message, data);
return false;
// AJAX不支持Redirect改用Forward
try {
String loginFailureUrl = Global.getProperty("adminPath")+"/loginFailure";
request.getRequestDispatcher(loginFailureUrl).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
}
public void setAuthorizingRealm(BaseAuthorizingRealm authorizingRealm) {
this.authorizingRealm = authorizingRealm;
return false;
}
/**
* 获取登录页面数据
* @author ThinkGem
*/
public static Map<String, Object> getLoginData(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> data = MapUtils.newHashMap();
@@ -294,7 +322,7 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
for (Entry<String, Object> entry : paramMap.entrySet()){
data.put(ServletUtils.EXT_PARAMS_PREFIX + entry.getKey(), entry.getValue());
}
// 如果已登录,再次访问主页,则退出原账号。
if (!Global.TRUE.equals(Global.getConfig("shiro.isAllowRefreshIndex"))){
CookieUtils.setCookie(response, "LOGINED", "false");
@@ -316,6 +344,10 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
return data;
}
/**
* 获取登录失败数据
* @author ThinkGem
*/
public static Map<String, Object> getLoginFailureData(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> data = MapUtils.newHashMap();
@@ -362,4 +394,9 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
data.put("result", Global.FALSE);
return data;
}
public void setAuthorizingRealm(BaseAuthorizingRealm authorizingRealm) {
this.authorizingRealm = authorizingRealm;
}
}

View File

@@ -38,7 +38,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
/**
* 系统安全认证实现类
* @author ThinkGem
* @version 2018-7-11
* @version 2020-9-19
*/
@SuppressWarnings("deprecation")
public class CasAuthorizingRealm extends BaseAuthorizingRealm {
@@ -92,7 +92,7 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
casToken.setUserId(casPrincipal.getName());
// 生成登录信息对象
FormToken token = new FormToken();
FormToken token = new FormToken(request);
token.setUsername(casPrincipal.getName());
Map<String, Object> params = MapUtils.newHashMap();
params.putAll(casPrincipal.getAttributes());

View File

@@ -37,14 +37,14 @@ import com.jeesite.modules.sys.utils.UserUtils;
/**
* 登录Controller
* @author ThinkGem
* @version 2020-4-13
* @version 2020-9-19
*/
@Controller
@RequestMapping(value = "${adminPath}")
public class LoginController extends BaseController{
/**
* 管理登录
* 登录页面
*/
@RequestMapping(value = "login", method = RequestMethod.GET)
public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
@@ -94,9 +94,9 @@ public class LoginController extends BaseController{
}
/**
* 登录失败,真正登录的POST请求由Filter完成
* 登录失败,返回错误信息
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
@RequestMapping(value = "loginFailure")
public String loginFailure(HttpServletRequest request, HttpServletResponse response, Model model) {
LoginInfo loginInfo = UserUtils.getLoginInfo();
@@ -200,6 +200,9 @@ public class LoginController extends BaseController{
// 获取登录成功后跳转的页面
String successUrl = request.getParameter("__url");
if (StringUtils.isBlank(successUrl)){
successUrl = (String)request.getAttribute("__url");
}
if (StringUtils.isBlank(successUrl)){
successUrl = Global.getProperty("shiro.successUrl");
}
@@ -272,16 +275,16 @@ public class LoginController extends BaseController{
}
/**
* 获取侧边栏菜单数据
* 侧边栏菜单数据
*/
@RequiresPermissions("user")
@RequestMapping(value = "index/menuTree")
public String indexMenuTree(String parentCode) {
return "modules/sys/sysIndex/menuTree";
return "modules/sys/menuTree";
}
/**
* 获取当前用户权限字符串数据(移动端用)
* 当前用户权限字符串数据(移动端用)
*/
@RequiresPermissions("user")
@RequestMapping(value = "authInfo")
@@ -291,7 +294,7 @@ public class LoginController extends BaseController{
}
/**
* 获取当前用户菜单数据(移动端用)
* 当前用户菜单数据(移动端用)
*/
@RequiresPermissions("user")
@RequestMapping(value = "menuTree")
@@ -334,7 +337,7 @@ public class LoginController extends BaseController{
}
/**
* 切换主题
* 切换主题风格
*/
@RequiresPermissions("user")
@RequestMapping(value = "switchSkin/{skinName}")

View File

@@ -18,6 +18,7 @@ import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.shiro.authc.FormToken;
import com.jeesite.common.shiro.filter.FormAuthenticationFilter;
import com.jeesite.common.web.BaseController;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.User;
@@ -26,7 +27,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
/**
* 单点登录Controller
* @author ThinkGem
* @version 2017-03-25
* @version 2020-9-19
*/
@Controller
public class SsoController extends BaseController{
@@ -63,24 +64,20 @@ public class SsoController extends BaseController{
// 通过令牌登录系统
if (token != null){
try {
FormToken upToken = new FormToken();
upToken.setUsername(username); // 登录用户名
upToken.setSsoToken(token); // 单点登录令牌
upToken.setParams(ServletUtils.getExtParams(request)); // 登录附加参数
UserUtils.getSubject().login(upToken);
if (ServletUtils.isAjaxRequest(request)){
return ServletUtils.renderResult(response, Global.TRUE, text("账号登录成功"));
}else{
return REDIRECT + EncodeUtils.decodeUrl2(url);
}
// FormToken 构造方法的三个参数:登录名、单点登录的令牌秘钥、请求对象
UserUtils.getSubject().login(new FormToken(username, token, request));
request.setAttribute("__url", EncodeUtils.decodeUrl2(url));
FormAuthenticationFilter.onLoginSuccess(request, response);
} catch (AuthenticationException e) {
if (!e.getMessage().startsWith("msg:")){
throw new AuthenticationException("msg:登录失败,请联系管理员。", e);
}
throw e;
FormAuthenticationFilter.onLoginFailure(e, request, response);
}
return null;
}
return "error/403";
}
// public static void main(String[] args) {
// System.out.println(UserUtils.getSsoToken("system"));
// }
}