rename prefix singleSign to cas

This commit is contained in:
thinkgem
2018-01-07 22:30:08 +08:00
parent c629a2005a
commit d08b54893c
11 changed files with 1437 additions and 1403 deletions

View File

@@ -1,75 +1,75 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package com.jeesite.common.shiro.realm;
import java.util.Map;
import org.apache.shiro.subject.PrincipalCollection;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.EmpUser;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.EmpUserService;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.LogUtils;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 系统安全认证实现类
* @author ThinkGem
* @version 2017-03-22
*/
public class AuthorizingRealm extends com.jeesite.common.shiro.realm.BaseAuthorizingRealm {
private UserService userService;
private EmpUserService empUserService;
public AuthorizingRealm() {
super();
}
@Override
protected void casCreateEmpUser(User user, Map<String, Object> attributes) {
EmpUser empUser = new EmpUser();
empUser.setIsNewRecord(true);
empUser.setMobile(user.getMobile());
empUser.setEmail(user.getEmail());
empUser.setPhone(user.getPhone());
empUser.getEmployee().getCompany().setCompanyCode(EncodeUtils
.decodeUrl(ObjectUtils.toString(attributes.get("companyCode"))));
empUser.getEmployee().getOffice().setOfficeCode(EncodeUtils
.decodeUrl(ObjectUtils.toString(attributes.get("officeCode"))));
empUserService.save(empUser);
}
@Override
public void onLoginSuccess(PrincipalCollection principals) {
super.onLoginSuccess(principals);
User user = UserUtils.getUser();
// 更新登录IP、时间、会话ID等
userService.updateUserLoginInfo(user);
// 记录用户登录日志
LogUtils.saveLog(ServletUtils.getRequest(), "系统登录");
}
@Override
public void onSingleSignOut(User logoutUser) {
// 记录用户退出日志
LogUtils.saveLog(logoutUser, null, null, null, "系统退出");
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setEmpUserService(EmpUserService empUserService) {
this.empUserService = empUserService;
}
}
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package com.jeesite.common.shiro.realm;
import java.util.Map;
import org.apache.shiro.subject.PrincipalCollection;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.EmpUser;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.EmpUserService;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.LogUtils;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 系统安全认证实现类
* @author ThinkGem
* @version 2017-03-22
*/
public class AuthorizingRealm extends com.jeesite.common.shiro.realm.BaseAuthorizingRealm {
private UserService userService;
private EmpUserService empUserService;
public AuthorizingRealm() {
super();
}
@Override
protected void casCreateEmpUser(User user, Map<String, Object> attributes) {
EmpUser empUser = new EmpUser();
empUser.setIsNewRecord(true);
empUser.setMobile(user.getMobile());
empUser.setEmail(user.getEmail());
empUser.setPhone(user.getPhone());
empUser.getEmployee().getCompany().setCompanyCode(EncodeUtils
.decodeUrl(ObjectUtils.toString(attributes.get("companyCode"))));
empUser.getEmployee().getOffice().setOfficeCode(EncodeUtils
.decodeUrl(ObjectUtils.toString(attributes.get("officeCode"))));
empUserService.save(empUser);
}
@Override
public void onLoginSuccess(PrincipalCollection principals) {
super.onLoginSuccess(principals);
User user = UserUtils.getUser();
// 更新登录IP、时间、会话ID等
userService.updateUserLoginInfo(user);
// 记录用户登录日志
LogUtils.saveLog(ServletUtils.getRequest(), "系统登录");
}
@Override
public void onLogoutSuccess(User logoutUser) {
// 记录用户退出日志
LogUtils.saveLog(logoutUser, null, null, null, "系统退出");
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setEmpUserService(EmpUserService empUserService) {
this.empUserService = empUserService;
}
}

View File

@@ -1,341 +1,341 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package com.jeesite.modules.sys.web;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.filter.FormAuthenticationFilter;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.web.BaseController;
import com.jeesite.common.web.CookieUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 登录Controller
* @author ThinkGem
* @version 2017-03-25
*/
@Controller
@RequestMapping(value = "${adminPath}")
public class LoginController extends BaseController{
/**
* 管理登录
*/
@RequestMapping(value = "login", method = RequestMethod.GET)
public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
// 地址中如果包含JSESSIONID则跳转一次去掉JSESSIONID信息。
if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/login" + queryString;
}
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 如果已经登录,则跳转到管理首页
if(loginInfo != null){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString;
if (ServletUtils.isAjaxRequest(request)){
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
}
// 如果是登录操作跳转到此则认为是登录失败支持GET登录时传递__login=true参数
if (WebUtils.isTrue(request, "__login")){
return loginFailure(request, response, model);
}
// 如果已登录,再次访问主页,则退出原账号。
if (!Global.TRUE.equals(Global.getConfig("shiro.isAllowRefreshIndex"))){
CookieUtils.setCookie(response, "LOGINED", "false");
}
// 是否显示验证码
model.addAttribute("isValidCodeLogin", ObjectUtils.toInteger(Global.getConfig("sys.login.failedNumAfterValidCode", "200")) == 0);
// 获取登录参数
Map<String, Object> paramMap = ServletUtils.getExtParams(request);
// 如果登录设置了语言,则切换语言
if (paramMap.get("lang") != null){
Global.setLang((String)paramMap.get("lang"), request, response);
}
// 如果是Ajax请求返回Json字符串。
if (ServletUtils.isAjaxRequest((HttpServletRequest)request)){
model.addAttribute("result", "login");
model.addAttribute("message", text("未登录或登录超时。请重新登录,谢谢!"));
return ServletUtils.renderObject(response, model);
}
// 返回指定用户类型的登录页视图
String userType = (String)paramMap.get("userType");
if (StringUtils.isNotBlank(userType)){
String view = UserUtils.getUserTypeValue(userType, "loginView");
if(StringUtils.isNotBlank(view)){
return view;
}
}
return "modules/sys/sysLogin";
}
/**
* 登录失败真正登录的POST请求由Filter完成
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
public String loginFailure(HttpServletRequest request, HttpServletResponse response, Model model) {
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 如果已经登录,则跳转到管理首页
if(loginInfo != null){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString;
if (ServletUtils.isAjaxRequest(request)){
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
}
String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
boolean rememberUserCode = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM);
String params = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_PARAMS_PARAM);
String exception = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
String message = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM);
model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);
model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe);
model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM, rememberUserCode);
model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAMS_PARAM, params);
Map<String, Object> paramMap = ServletUtils.getExtParams(request);
for (Entry<String, Object> entry : paramMap.entrySet()){
model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAM_PREFIX_PARAM + entry.getKey(), entry.getValue());
}
model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception);
// 如果登录设置了语言,则切换语言
if (paramMap.get("lang") != null){
Global.setLang((String)paramMap.get("lang"), request, response);
}
model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, text(message));
// 非授权异常登录失败验证码加1。
if (!UnauthorizedException.class.getName().equals(exception)){
// // 如果使用了集团用户模式则获取集团Code
// String corpCode = null;
// if (Global.isUseCorpModel()){
// corpCode = (String)paramMap.get("corpCode");
// if (StringUtils.isBlank(corpCode)){
// throw new AuthenticationException("msg:请选择您要登录的集团公司.");
// }
// }
model.addAttribute("isValidCodeLogin", BaseAuthorizingRealm.isValidCodeLogin(username, /*corpCode, */(String)paramMap.get("deviceType"), "failed"));
}
// 登录操作如果是Ajax操作直接返回登录信息字符串。
if (ServletUtils.isAjaxRequest(request)){
model.addAttribute("result", Global.FALSE);
return ServletUtils.renderObject(response, model);
}
// 返回指定用户类型的登录页视图
String userType = (String)paramMap.get("userType");
if (StringUtils.isNotBlank(userType)){
String view = UserUtils.getUserTypeValue(userType, "loginView");
if(StringUtils.isNotBlank(view)){
return view;
}
}
return "modules/sys/sysLogin";
}
/**
* 登录成功,进入管理首页
*/
@RequestMapping(value = "index")
public String index(HttpServletRequest request, HttpServletResponse response, Model model) {
// 地址中如果包含JSESSIONID则跳转一次去掉JSESSIONID信息。
if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/index" + queryString;
}
// 验证下用户权限以便调用doGetAuthorizationInfo方法保存单点登录登出句柄
if (!SecurityUtils.getSubject().isPermitted("user")){
return REDIRECT + adminPath + "/login";
}
//获取登录用户信息
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 未加载shiro模块时会为空直接访问则提示操作权限不足。
if(loginInfo == null){
UserUtils.getSubject().logout();
return REDIRECT + adminPath + "/login";
}
// 当前用户对象信息
User user = UserUtils.get(loginInfo.getId());
if (user == null){
UserUtils.getSubject().logout();
return REDIRECT + adminPath + "/login";
}
model.addAttribute("user", user); // 设置当前用户信息
// 登录成功后,验证码计算器清零
BaseAuthorizingRealm.isValidCodeLogin(loginInfo.getId(), /*loginInfo.getParam("corpCode"), */loginInfo.getParam("deviceType"), "success");
//获取当前会话对象
Session session = UserUtils.getSession();
// 设置共享SessionId的Cookie值睿思BI使用。
String cookieName = Global.getProperty("session.shareSessionIdCookieName");
CookieUtils.setCookie((HttpServletResponse)response, cookieName, (String)session.getId());
// 如果是登录操作,则设置登录信息(移动端用)
model.addAttribute("result", Global.TRUE);
if (request.getParameter("username") != null && request.getParameter("password") != null){
// 如果登录设置了语言,则切换语言
if (loginInfo.getParam("lang") != null){
Global.setLang(loginInfo.getParam("lang"), request, response);
}
model.addAttribute("message", text("登录成功!"));
}else{
model.addAttribute("message", text("获取信息成功!"));
}
model.addAttribute("sessionid", (String)session.getId());
// 授权信息获取
AuthorizationInfo authInfo = null;
// 获取当前用户权限字符串
if (WebUtils.isTrue(request, "permi")){
if (authInfo == null){
authInfo = (AuthorizationInfo)UserUtils.getCache(UserUtils.CACHE_AUTH_INFO);
}
model.addAttribute("permi", authInfo.getStringPermissions());
}
// 登录操作如果是Ajax操作直接返回登录信息字符串。
if (ServletUtils.isAjaxRequest(request)){
return ServletUtils.renderObject(response, model);
}
// 是否允许刷新主页,如果已登录,再次访问主页,则退出原账号。
if (!ObjectUtils.toBoolean(Global.getConfig("shiro.isAllowRefreshIndex", "true"))){
String logined = CookieUtils.getCookie(request, "LOGINED");
if (StringUtils.isBlank(logined) || "false".equals(logined)){
CookieUtils.setCookie(response, "LOGINED", "true");
}else if (StringUtils.equals(logined, "true")){
UserUtils.getSubject().logout();
CookieUtils.setCookie(response, "LOGINED", "false");
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/login" + queryString;
}
}
// 初始密码策略和密码修改策略验证0关闭1提醒用户2强制修改初始或旧密码
String passwordModifyUrl = UserService.passwordModifyValid(user, model);
if (passwordModifyUrl != null){
try {
request.getRequestDispatcher(passwordModifyUrl).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 返回指定用户类型的首页视图
String view = UserUtils.getUserTypeValue(user.getUserType(), "indexView");
if(StringUtils.isNotBlank(view)){
return view;
}
// 返回主页面视图
return "modules/sys/sysIndex";
}
/**
* 切换系统菜单(仅超级管理员有权限)
*/
@RequiresPermissions("user")
@RequestMapping(value = "switch/{sysCode}")
public String switchSys(@PathVariable String sysCode) {
LoginInfo principal = UserUtils.getLoginInfo();
User user = UserUtils.get(principal.getId());
if (user.isSuperAdmin() && StringUtils.isNotBlank(sysCode)){
if (!StringUtils.equals(principal.getParam("sysCode"), sysCode)){
principal.setParam("sysCode", sysCode);
UserUtils.removeCache(UserUtils.CACHE_AUTH_INFO);
UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
}
}
return REDIRECT + adminPath + "/index";
}
/**
* 切换主题
*/
@RequiresPermissions("user")
@RequestMapping(value = "switchSkin/{skinName}")
public String switchSkin(@PathVariable String skinName, HttpServletRequest request, HttpServletResponse response) {
LoginInfo loginInfo = UserUtils.getLoginInfo();
if (StringUtils.isNotBlank(skinName) && !"select".equals(skinName)){
CookieUtils.setCookie(response, "skinName_" + loginInfo.getId(), skinName);
return REDIRECT + adminPath + "/index";
}
return "modules/sys/sysSwitchSkin";
}
/**
* 个人桌面页面
*/
@RequiresPermissions("user")
@RequestMapping(value = "desktop")
public String desktop(HttpServletRequest request, HttpServletResponse response, Model model) {
return "modules/sys/sysDesktop";
}
}
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package com.jeesite.modules.sys.web;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.filter.FormAuthenticationFilter;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.web.BaseController;
import com.jeesite.common.web.CookieUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 登录Controller
* @author ThinkGem
* @version 2017-03-25
*/
@Controller
@RequestMapping(value = "${adminPath}")
public class LoginController extends BaseController{
/**
* 管理登录
*/
@RequestMapping(value = "login", method = RequestMethod.GET)
public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
// // 地址中如果包含JSESSIONID则跳转一次去掉JSESSIONID信息。
// if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
// String queryString = request.getQueryString();
// queryString = queryString == null ? "" : "?" + queryString;
// return REDIRECT + adminPath + "/login" + queryString;
// }
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 如果已经登录,则跳转到管理首页
if(loginInfo != null){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString;
if (ServletUtils.isAjaxRequest(request)){
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
}
// 如果是登录操作跳转到此则认为是登录失败支持GET登录时传递__login=true参数
if (WebUtils.isTrue(request, "__login")){
return loginFailure(request, response, model);
}
// 如果已登录,再次访问主页,则退出原账号。
if (!Global.TRUE.equals(Global.getConfig("shiro.isAllowRefreshIndex"))){
CookieUtils.setCookie(response, "LOGINED", "false");
}
// 是否显示验证码
model.addAttribute("isValidCodeLogin", ObjectUtils.toInteger(Global.getConfig("sys.login.failedNumAfterValidCode", "200")) == 0);
// 获取登录参数
Map<String, Object> paramMap = ServletUtils.getExtParams(request);
// 如果登录设置了语言,则切换语言
if (paramMap.get("lang") != null){
Global.setLang((String)paramMap.get("lang"), request, response);
}
// 如果是Ajax请求返回Json字符串。
if (ServletUtils.isAjaxRequest((HttpServletRequest)request)){
model.addAttribute("result", "login");
model.addAttribute("message", text("未登录或登录超时。请重新登录,谢谢!"));
return ServletUtils.renderObject(response, model);
}
// 返回指定用户类型的登录页视图
String userType = (String)paramMap.get("userType");
if (StringUtils.isNotBlank(userType)){
String view = UserUtils.getUserTypeValue(userType, "loginView");
if(StringUtils.isNotBlank(view)){
return view;
}
}
return "modules/sys/sysLogin";
}
/**
* 登录失败真正登录的POST请求由Filter完成
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
public String loginFailure(HttpServletRequest request, HttpServletResponse response, Model model) {
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 如果已经登录,则跳转到管理首页
if(loginInfo != null){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString;
if (ServletUtils.isAjaxRequest(request)){
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
}
String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
boolean rememberUserCode = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM);
String params = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_PARAMS_PARAM);
String exception = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
String message = (String)request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM);
model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);
model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe);
model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_USERCODE_PARAM, rememberUserCode);
model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAMS_PARAM, params);
Map<String, Object> paramMap = ServletUtils.getExtParams(request);
for (Entry<String, Object> entry : paramMap.entrySet()){
model.addAttribute(FormAuthenticationFilter.DEFAULT_PARAM_PREFIX_PARAM + entry.getKey(), entry.getValue());
}
model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception);
// 如果登录设置了语言,则切换语言
if (paramMap.get("lang") != null){
Global.setLang((String)paramMap.get("lang"), request, response);
}
model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, text(message));
// 非授权异常登录失败验证码加1。
if (!UnauthorizedException.class.getName().equals(exception)){
// // 如果使用了集团用户模式则获取集团Code
// String corpCode = null;
// if (Global.isUseCorpModel()){
// corpCode = (String)paramMap.get("corpCode");
// if (StringUtils.isBlank(corpCode)){
// throw new AuthenticationException("msg:请选择您要登录的集团公司.");
// }
// }
model.addAttribute("isValidCodeLogin", BaseAuthorizingRealm.isValidCodeLogin(username, /*corpCode, */(String)paramMap.get("deviceType"), "failed"));
}
// 登录操作如果是Ajax操作直接返回登录信息字符串。
if (ServletUtils.isAjaxRequest(request)){
model.addAttribute("result", Global.FALSE);
return ServletUtils.renderObject(response, model);
}
// 返回指定用户类型的登录页视图
String userType = (String)paramMap.get("userType");
if (StringUtils.isNotBlank(userType)){
String view = UserUtils.getUserTypeValue(userType, "loginView");
if(StringUtils.isNotBlank(view)){
return view;
}
}
return "modules/sys/sysLogin";
}
/**
* 登录成功,进入管理首页
*/
@RequestMapping(value = "index")
public String index(HttpServletRequest request, HttpServletResponse response, Model model) {
// // 地址中如果包含JSESSIONID则跳转一次去掉JSESSIONID信息。
// if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
// String queryString = request.getQueryString();
// queryString = queryString == null ? "" : "?" + queryString;
// return REDIRECT + adminPath + "/index" + queryString;
// }
// 验证下用户权限以便调用doGetAuthorizationInfo方法保存单点登录登出句柄
if (!SecurityUtils.getSubject().isPermitted("user")){
return REDIRECT + adminPath + "/login";
}
//获取登录用户信息
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 未加载shiro模块时会为空直接访问则提示操作权限不足。
if(loginInfo == null){
UserUtils.getSubject().logout();
return REDIRECT + adminPath + "/login";
}
// 当前用户对象信息
User user = UserUtils.get(loginInfo.getId());
if (user == null){
UserUtils.getSubject().logout();
return REDIRECT + adminPath + "/login";
}
model.addAttribute("user", user); // 设置当前用户信息
// 登录成功后,验证码计算器清零
BaseAuthorizingRealm.isValidCodeLogin(loginInfo.getId(), /*loginInfo.getParam("corpCode"), */loginInfo.getParam("deviceType"), "success");
//获取当前会话对象
Session session = UserUtils.getSession();
// 设置共享SessionId的Cookie值睿思BI使用。
String cookieName = Global.getProperty("session.shareSessionIdCookieName");
CookieUtils.setCookie((HttpServletResponse)response, cookieName, (String)session.getId());
// 如果是登录操作,则设置登录信息(移动端用)
model.addAttribute("result", Global.TRUE);
if (request.getParameter("username") != null && request.getParameter("password") != null){
// 如果登录设置了语言,则切换语言
if (loginInfo.getParam("lang") != null){
Global.setLang(loginInfo.getParam("lang"), request, response);
}
model.addAttribute("message", text("登录成功!"));
}else{
model.addAttribute("message", text("获取信息成功!"));
}
model.addAttribute("sessionid", (String)session.getId());
// 授权信息获取
AuthorizationInfo authInfo = null;
// 获取当前用户权限字符串
if (WebUtils.isTrue(request, "permi")){
if (authInfo == null){
authInfo = (AuthorizationInfo)UserUtils.getCache(UserUtils.CACHE_AUTH_INFO);
}
model.addAttribute("permi", authInfo.getStringPermissions());
}
// 登录操作如果是Ajax操作直接返回登录信息字符串。
if (ServletUtils.isAjaxRequest(request)){
return ServletUtils.renderObject(response, model);
}
// 是否允许刷新主页,如果已登录,再次访问主页,则退出原账号。
if (!ObjectUtils.toBoolean(Global.getConfig("shiro.isAllowRefreshIndex", "true"))){
String logined = CookieUtils.getCookie(request, "LOGINED");
if (StringUtils.isBlank(logined) || "false".equals(logined)){
CookieUtils.setCookie(response, "LOGINED", "true");
}else if (StringUtils.equals(logined, "true")){
UserUtils.getSubject().logout();
CookieUtils.setCookie(response, "LOGINED", "false");
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/login" + queryString;
}
}
// 初始密码策略和密码修改策略验证0关闭1提醒用户2强制修改初始或旧密码
String passwordModifyUrl = UserService.passwordModifyValid(user, model);
if (passwordModifyUrl != null){
try {
request.getRequestDispatcher(passwordModifyUrl).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 返回指定用户类型的首页视图
String view = UserUtils.getUserTypeValue(user.getUserType(), "indexView");
if(StringUtils.isNotBlank(view)){
return view;
}
// 返回主页面视图
return "modules/sys/sysIndex";
}
/**
* 切换系统菜单(仅超级管理员有权限)
*/
@RequiresPermissions("user")
@RequestMapping(value = "switch/{sysCode}")
public String switchSys(@PathVariable String sysCode) {
LoginInfo principal = UserUtils.getLoginInfo();
User user = UserUtils.get(principal.getId());
if (user.isSuperAdmin() && StringUtils.isNotBlank(sysCode)){
if (!StringUtils.equals(principal.getParam("sysCode"), sysCode)){
principal.setParam("sysCode", sysCode);
UserUtils.removeCache(UserUtils.CACHE_AUTH_INFO);
UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
}
}
return REDIRECT + adminPath + "/index";
}
/**
* 切换主题
*/
@RequiresPermissions("user")
@RequestMapping(value = "switchSkin/{skinName}")
public String switchSkin(@PathVariable String skinName, HttpServletRequest request, HttpServletResponse response) {
LoginInfo loginInfo = UserUtils.getLoginInfo();
if (StringUtils.isNotBlank(skinName) && !"select".equals(skinName)){
CookieUtils.setCookie(response, "skinName_" + loginInfo.getId(), skinName);
return REDIRECT + adminPath + "/index";
}
return "modules/sys/sysSwitchSkin";
}
/**
* 个人桌面页面
*/
@RequiresPermissions("user")
@RequestMapping(value = "desktop")
public String desktop(HttpServletRequest request, HttpServletResponse response, Model model) {
return "modules/sys/sysDesktop";
}
}

View File

@@ -1,151 +1,151 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package com.jeesite.modules.sys.web;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.beust.jcommander.internal.Lists;
import com.beust.jcommander.internal.Maps;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.lang.TimeUtils;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.shiro.session.SessionDAO;
import com.jeesite.common.web.BaseController;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 在线用户Controller
* @author ThinkGem
* @version 2016-8-31
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/online")
public class OnlineController extends BaseController{
@Autowired
private SessionDAO sessionDAO;
/**
* 在线用户数
* @param request
* @param response
* @author ThinkGem
*/
@RequestMapping(value = "count")
@ResponseBody
public Integer count(HttpServletRequest request, HttpServletResponse response) {
return sessionDAO.getActiveSessions(true, true).size();
}
/**
* 在线用户列表
* @param request
* @param response
* @param model
*/
@RequiresPermissions("sys:online:view")
@RequestMapping(value = "list")
public String list(Model model) {
return "modules/sys/onlineList";
}
/**
* 在线用户列表数据
* @param request
* @param response
* @author ThinkGem
*/
@RequiresPermissions("sys:online:view")
@RequestMapping(value = "listData")
@ResponseBody
public List<Map<String, Object>> listData(@RequestParam(defaultValue="true") Boolean excludeLeave,
@RequestParam(defaultValue="true") Boolean excludeVisitor, String sessionId, String userCode,
String userName, String userType, String orderBy) {
List<Map<String, Object>> list = Lists.newArrayList();
Collection<Session> sessions = sessionDAO.getActiveSessions(excludeLeave, excludeVisitor, null, sessionId, userCode);
long currentTime = System.currentTimeMillis();
for (Session session : sessions){
if (StringUtils.isNotBlank(userName) && ((String)session.getAttribute("userName")).contains(userName)){
continue;
}
if (StringUtils.isNotBlank(userType) && ((String)session.getAttribute("userType")).equals(userType)){
continue;
}
Map<String, Object> map = Maps.newLinkedHashMap();
// 为了安全性,需要有权限的人才能看
if (UserUtils.getSubject().isPermitted("sys:online:edit")){
map.put("id", session.getId().toString());
}
map.put("startTimestamp", DateUtils.formatDateTime(session.getStartTimestamp()));
map.put("lastAccessTime", DateUtils.formatDateTime(session.getLastAccessTime()));
map.put("timeout", TimeUtils.formatDateAgo(session.getTimeout()-(currentTime-session.getLastAccessTime().getTime())));
PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
LoginInfo principal = (pc != null ? (LoginInfo)pc.getPrimaryPrincipal() : null);
if (principal != null){
map.put("userCode", session.getAttribute("userCode"));// principal.getId());
map.put("userName", session.getAttribute("userName"));// principal.getName());
map.put("userType", session.getAttribute("userType"));// ObjectUtils.toString(principal.getParam("userType")));
map.put("deviceType", ObjectUtils.toString(principal.getParam("deviceType")));
}
map.put("host", session.getHost());
list.add(map);
}
// 本地排序
if (StringUtils.isNotBlank(orderBy)){
final String[] ss = orderBy.trim().split(" ");
if (ss != null && ss.length == 2){
Collections.sort(list, new Comparator<Map<String, Object>>() {
@Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
String s1 = (String)o1.get(ss[0]);
String s2 = (String)o2.get(ss[0]);
if ("asc".equals(ss[1])){
return s1.compareTo(s2);
}else{
return s2.compareTo(s1);
}
}});
}
}
return list;
}
/**
* 提出在线用户
* @author ThinkGem
*/
@RequiresPermissions("sys:online:edit")
@RequestMapping(value = "tickOut")
@ResponseBody
public String tickOut(String sessionId) {
Session session = sessionDAO.readSession(sessionId);
if (session != null){
sessionDAO.delete(session);
return renderResult(Global.TRUE, "踢出已成功!");
}
return renderResult(Global.FALSE, "踢出失败,没有找到该在线用户!");
}
}
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package com.jeesite.modules.sys.web;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.beust.jcommander.internal.Lists;
import com.beust.jcommander.internal.Maps;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.lang.TimeUtils;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.shiro.session.SessionDAO;
import com.jeesite.common.web.BaseController;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 在线用户Controller
* @author ThinkGem
* @version 2016-8-31
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/online")
public class OnlineController extends BaseController{
@Autowired
private SessionDAO sessionDAO;
/**
* 在线用户数
* @param request
* @param response
* @author ThinkGem
*/
@RequestMapping(value = "count")
@ResponseBody
public Integer count(HttpServletRequest request, HttpServletResponse response) {
return sessionDAO.getActiveSessions(true, true).size();
}
/**
* 在线用户列表
* @param request
* @param response
* @param model
*/
@RequiresPermissions("sys:online:view")
@RequestMapping(value = "list")
public String list(Model model) {
return "modules/sys/onlineList";
}
/**
* 在线用户列表数据
* @param request
* @param response
* @author ThinkGem
*/
@RequiresPermissions("sys:online:view")
@RequestMapping(value = "listData")
@ResponseBody
public List<Map<String, Object>> listData(@RequestParam(defaultValue="true") Boolean excludeLeave,
@RequestParam(defaultValue="true") Boolean excludeVisitor, String sessionId, String userCode,
String userName, String userType, String orderBy) {
List<Map<String, Object>> list = Lists.newArrayList();
Collection<Session> sessions = sessionDAO.getActiveSessions(excludeLeave, excludeVisitor, null, sessionId, userCode);
long currentTime = System.currentTimeMillis();
for (Session session : sessions){
if (StringUtils.isNotBlank(userName) && ((String)session.getAttribute("userName")).contains(userName)){
continue;
}
if (StringUtils.isNotBlank(userType) && ((String)session.getAttribute("userType")).equals(userType)){
continue;
}
Map<String, Object> map = Maps.newLinkedHashMap();
// 为了安全性,需要有权限的人才能看
if (UserUtils.getSubject().isPermitted("sys:online:edit")){
map.put("id", session.getId().toString());
}
map.put("startTimestamp", DateUtils.formatDateTime(session.getStartTimestamp()));
map.put("lastAccessTime", DateUtils.formatDateTime(session.getLastAccessTime()));
map.put("timeout", TimeUtils.formatDateAgo(session.getTimeout()-(currentTime-session.getLastAccessTime().getTime())));
PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
LoginInfo principal = (pc != null ? (LoginInfo)pc.getPrimaryPrincipal() : null);
if (principal != null){
map.put("userCode", session.getAttribute("userCode"));// principal.getId());
map.put("userName", session.getAttribute("userName"));// principal.getName());
map.put("userType", session.getAttribute("userType"));// ObjectUtils.toString(principal.getParam("userType")));
map.put("deviceType", ObjectUtils.toString(principal.getParam("deviceType")));
}
map.put("host", session.getHost());
list.add(map);
}
// 本地排序
if (StringUtils.isNotBlank(orderBy)){
final String[] ss = orderBy.trim().split(" ");
if (ss != null && ss.length == 2){
Collections.sort(list, new Comparator<Map<String, Object>>() {
@Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
String s1 = (String)o1.get(ss[0]);
String s2 = (String)o2.get(ss[0]);
if ("asc".equals(ss[1])){
return s1.compareTo(s2);
}else{
return s2.compareTo(s1);
}
}});
}
}
return list;
}
/**
* 提出在线用户
* @author ThinkGem
*/
@RequiresPermissions("sys:online:edit")
@RequestMapping(value = "tickOut")
@ResponseBody
public String tickOut(String sessionId) {
Session session = sessionDAO.readSession(sessionId);
if (session != null){
sessionDAO.delete(session);
return renderResult(Global.TRUE, "踢出已成功!");
}
return renderResult(Global.FALSE, "踢出失败,没有找到该在线用户!");
}
}

View File

@@ -1,428 +1,428 @@
#============================#
#===== Database sttings =====#
#============================#
# 数据库连接
jdbc:
# Oracle 数据库配置
type: oracle
driver: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
username: jeesite
password: jeesite
testSql: SELECT 1 FROM DUAL
# Mysql 数据库配置
# type: mysql
# driver: com.mysql.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/jeesite?useUnicode=true&characterEncoding=utf-8
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# Sql Server 数据库配置
# type: mssql
# driver: net.sourceforge.jtds.jdbc.Driver
# url: jdbc:jtds:sqlserver://127.0.0.1:1433/jeesite
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# PostgreSql 数据库配置
# type: postgre
# driver: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/jeesite
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# 连接信息加密
encrypt:
# 加密连接用户名
username: false
# 加密连接密码
password: true
# 数据库连接池配置
pool:
# 初始化连接数
init: 1
# 最小连接数
minIdle: 3
# 最大连接数
maxActive: 20
# 表名前缀
tablePrefix: js_
# # 多数数据源名称列表调用方式DataSourceHolder.setDataSourceName("ds2")
# dataSourceNames: ds2
#
# # 多数据源配置ds2
# ds2:
# type: oracle
# driver: oracle.jdbc.driver.OracleDriver
# url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
# username: jeesite
# password: jeesite
# encryptUsername: false
# encryptPassword: true
# pool:
# init: 1
# minIdle: 3
# maxActive: 20
# Redis 配置
redis:
# Redis 连接参数
host: 127.0.0.1
port: 6379
password: 1234
database: 0
# 定义Key的前缀标识
keyPrefix: jeesite
# Redis 连接池配置
pool:
maxIdle: 3
maxTotal: 20
# Mapper文件刷新线程
mapperRefresh:
enabled: true
delaySeconds: 60
sleepSeconds: 3
mappingPath: mappings
#============================#
#===== System settings ======#
#============================#
#产品信息设置
productName: JeeSite Demo
productVersion: V4.0
copyrightYear: 2018
companyName: ThinkGem
#是否演示模式
demoMode: false
#管理基础路径
adminPath: /a
#前端基础路径
frontPath: /f
#索引页路径
defaultPath: ${adminPath}/login
# 用户相关参数
user:
# 指定超级管理员编号(实施人员,开发团队使用的用户)
superAdminCode: thinkgem
# 超级管理员获取菜单的最小权重默认20>=40二级管理员>=60系统管理员>=80超级管理员
superAdminGetMenuMinWeight: 40
# 系统管理员角色编号(客户方使用的角色,客户方管理员)
corpAdminRoleCode: corpAdmin
# 用户类型配置信息employee员工member会员btype往来单位persion个人expert专家...
# JSON格式说明{"用户类型":{"dao":"Dao的Bean名称","loginView":"登录视图","indexView":"主页框架面视图"}}
userTypeMap: >
{
"employee":{"dao":"employeeDao","loginView":"","indexView":""},
"member":{"dao":"memberDao","loginView":"","indexView":"modules/sys/sysIndexMember"},
"btype":{"dao":"btypeInfoDao","loginView":"","indexView":"modules/sys/sysIndexBtype"},
"persion":{"dao":"persionDao","loginView":"","indexView":"modules/sys/sysIndexPersion"},
"expert":{"dao":"expertDao","loginView":"","indexView":"modules/sys/sysIndexExpert"}
}
# 数据权限设置参数可新增自定义数据权限moduleCode: 针对模块, ctrlPermi: 权限类型, 0全部 1拥有权限 2管理权限
dataScopes: >
[{
moduleCode: "core",
ctrlPermi: "0",
ctrlName: "部门权限",
ctrlType: "Office",
ctrlDataUrl: "/sys/office/treeData",
chkboxType: {"Y":"ps","N":"ps"},
remarks: ""
},{
moduleCode: "core",
ctrlName: "公司权限",
ctrlType: "Company",
ctrlPermi: "0",
ctrlDataUrl: "/sys/company/treeData",
chkboxType: {"Y":"ps","N":"ps"},
remarks: ""
},{
moduleCode: "core",
ctrlName: "角色权限",
ctrlType: "Role",
ctrlPermi: "2",
ctrlDataUrl: "/sys/role/treeData",
chkboxType: {"Y":"ps","N":"ps"},
remarks: ""
}]
# 集团模式多公司、多租户、SAAS模式
useCorpModel: false
# 分页配置
page:
# 分页默认大小
pageSize: 20
# 任务调度
job:
# 是否自动启动任务调度(集群情况下开启一个服务)
autoStartup: true
# 任务调度启动延迟设置(单位:秒)(建议设置项目启动完成后的时间)
startupDelay: 60
# 内容管理
cms:
# 内容管理主站点编码
mainSiteCode: main
#============================#
#==== Framework settings ====#
#============================#
# Shiro 相关配置
shiro:
# 登录相关设置
loginUrl: ${adminPath}/login
logoutUrl: ${shiro.loginUrl}
successUrl: ${adminPath}/index
# CAS 相关配置
casServerUrl: http://192.168.1.3:8080/cas
casClientUrl: http://192.168.1.3:8180/jeesite
# loginUrl: ${shiro.casServerUrl}?service=${shiro.casClientUrl}${adminPath}/login-cas
# logoutUrl: ${shiro.casServerUrl}/logout?service=${shiro.loginUrl}
# successUrl: ${shiro.casClientUrl}
# SSO 登录相关配置
sso:
# 如果启用/sso/{username}/{token}单点登录请修改此安全key并与单点登录系统key一致。
secretKey: abc
# 是否加密单点登录安全Key
encryptKey: true
# 登录提交信息加密
loginSubmit:
# 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔
secretKey: thinkgem,jeesite,com
# 是否允许账号多地登录如果设置为false同一个设备类型的其它地点登录的相同账号被踢下线
isAllowMultiAddrLogin: true
# 是否允许刷新主框架页如果设置为false刷新主页将导致重新登录。如安全性比较高的如银行个人首页不允许刷新。
isAllowRefreshIndex: true
# 是否允许嵌入到外部网站iframe中true不限制false不允许
isAllowExternalSiteIframe: true
# 是否允许跨域访问,如果允许,设置允许的域名,全部域名设置*号,如果不允许,此设置应该为空
# accessControlAllowOrigin: http://demo.jeesite.com
# accessControlAllowOrigin: '*'
# URI 权限过滤器定义
filterChainDefinitions: |
/ReportServer/** = user
${adminPath}/** = user
# filterChainDefinitions: |
# /ReportServer/** = user
# ${adminPath}/file/** = anon
# ${adminPath}/cms/* = anon
# ${adminPath}/cms/site/select = anon
# ${adminPath}/cms/site/* = anon
# ${adminPath}/cms/category/treeData = anon
# ${adminPath}/cms/category/* = anon
# ${adminPath}/cms/article/* = anon
# ${adminPath}/cms/link/* = anon
# ${adminPath}/** = user
# 默认的授权过滤定义如果在filterChainDefinitions中已经定义则该定义会被覆盖。
defaultFilterChainDefinitions: |
/static/** = anon
/userfiles/** = anon
/druid/** = perms[state:druid]
${adminPath}/login-cas = cas
${adminPath}/login = authc
${adminPath}/logout = logout
${adminPath}/file/** = user
${adminPath}/cms/* = perms[cms:view]
${adminPath}/cms/site/select = user
${adminPath}/cms/site/* = perms[cms:site:view]
${adminPath}/cms/category/treeData = user
${adminPath}/cms/category/* = perms[cms:category:view]
${adminPath}/cms/article/* = perms[cms:article:view]
${adminPath}/cms/link/* = perms[cms:link:view]
# Session 相关
session:
#全局会话超时,单位:毫秒, 20m=1200000ms, 30m=1800000ms, 60m=3600000ms, 12h=43200000ms, 1day=86400000ms
sessionTimeout: 1800000
#手机APP设备会话超时参数设置登录请求参数加 param_deviceType=mobileApp 时有效
mobileAppSessionTimeout: 43200000
#定时清理失效会话,清理用户直接关闭浏览器造成的孤立会话
sessionTimeoutClean: 1200000
#会话唯一标识SessionId在Cookie中的名称。
sessionIdCookieName: jeesite.session.id
#共享的SessionId的Cookie名称保存到跟路径下第三方应用获取。同一域名下多个项目时需设置共享Cookie的名称。
shareSessionIdCookieName: jeesite.session.id
# MyBatis 相关
mybatis:
# 扫描基础包设置Aliases、@MyBatisDao如果多个用“,”分隔
scanBasePackage: com.jeesite.modules
# 缓存设置
ehcache:
# 缓存配置文件路径
configFile: cache/ehcache-local.xml
# configFile: cache/ehcache-rmi.xml
# 清理缓存的缓存名称
clearNames: sysCache,userCache,corpCache,cmsCache,pageCachingFilter
# Web 相关
web:
# MVC 视图相关
view:
# 系统主题名称,主题视图优先级最高,如果主题下无这个视图文件则访问默认视图
# 引入页面头部:'/themes/'+themeName+'/include/header.html'
# 引入页面为不:'/themes/'+themeName+'/include/footer.html'
themeName: default
# 静态文件后缀,过滤静态文件,以提高访问性能。
staticFile: .css,.js,.map,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.crx,.xpi,.exe,.ipa,.apk,.otf,.eot,.svg,.ttf,.woff,.woff2
# 静态文件后缀排除的url路径指定哪些uri路径不进行静态文件过滤。
staticFileExcludeUri: /druid/
# 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false
error:
page:
printErrorInfo: true
#============================#
#=== FileUpload settings ====#
#============================#
file:
# 文件上传跟路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径
# baseDir: D:/jeesite
# 上传文件的相对路径支持yyyy, MM, dd, HH, mm, ss, E
uploadPath: '{yyyy}{MM}/'
# 上传单个文件最大字节500M在这之上还有 > Tomcat限制 > Nginx限制等。
maxFileSize: 500*1024*1024
#设置允许上传的文件后缀
imageAllowSuffixes: .gif,.bmp,.jpeg,.jpg,.ico,.png,.tif,.tiff,
mediaAllowSuffixes: .flv,.swf,.mkv,webm,.mid,.mov,.mp3,.mp4,.m4v,.mpc,.mpeg,.mpg,.swf,.wav,.wma,.wmv,.avi,.rm,.rmi,.rmvb,.aiff,.asf,.ogg,.ogv,
fileAllowSuffixes: .doc,.docx,.rtf,.xls,.xlsx,.csv,.ppt,.pptx,.pdf,.vsd,.txt,.md,.xml,.rar,.zip,7z,.tar,.tgz,.jar,.gz,.gzip,.bz2,.cab,.iso,
#允许上传的文件内容类型图片、word、excel、ppt防止修改后缀恶意上传文件默认不启用验证
# allowContentTypes: image/jpeg,image/gif,image/bmp,image/png,image/x-png,
# application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,
# application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
# application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation
#============================#
#===== Message settings =====#
#============================#
msg:
# 是否开启实时发送消息(保存消息后立即检查未读消息并发送),分布式部署下请单独配置消息发送服务,不建议开启此选项。
realtime:
# 是否开启
enabled: true
# 消息发送任务Bean名称
sendTaskBeanName: msgLocalSendTask
# 邮件发送参数
email:
fromAddress: jeesite_demo@163.com
fromPassword: jeesitedemo1234
fromHostName: smtp.163.com
sslOnConnect: false
sslSmtpPort: 994
# 短信网关
sms:
url: http://host:port/msg/sendSms
data: account=demo&pswd=demo&product=
suffix: 【JeeSite】
# 微信相关
weixin:
#微信应用ID
appid: ~
#微信应用密钥
secret: ~
# 微信服务器配置
server:
# 微信服务器配置Token
token: ~
# 微信服务器配置EncodingAESKey
aeskey: ~
# 微信服务器是否开启Debug模式开启后发送未知消息时候会返回消息内容
debug: true
# 微信OAuth登录授权回调地址
oauth:
redirectUri: http://demo.jeesite.com/jeesite
#============================#
#===== Video settings =======#
#============================#
video:
# 视频格式转换 ffmpeg.exe 所放的路径
ffmpegFile: d:/tools/video/ffmpeg-4.9/bin/ffmpeg.exe
# ffmpegFile: d:/tools/video/libav-10.6-win64/bin/avconv.exe
# 视频格式转换 mencoder.exe 所放的路径
mencoderFile: d:/tools/video/mencoder-4.9/mencoder.exe
# 将mp4视频的元数据信息转到视频第一帧
qtFaststartFile: d:/tools/video/qt-faststart/qt-faststart.exe
#============================#
#===== Project settings =====#
#============================#
#============================#
#===== Database sttings =====#
#============================#
# 数据库连接
jdbc:
# Oracle 数据库配置
type: oracle
driver: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
username: jeesite
password: jeesite
testSql: SELECT 1 FROM DUAL
# Mysql 数据库配置
# type: mysql
# driver: com.mysql.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/jeesite?useUnicode=true&characterEncoding=utf-8
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# Sql Server 数据库配置
# type: mssql
# driver: net.sourceforge.jtds.jdbc.Driver
# url: jdbc:jtds:sqlserver://127.0.0.1:1433/jeesite
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# PostgreSql 数据库配置
# type: postgre
# driver: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/jeesite
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# 连接信息加密
encrypt:
# 加密连接用户名
username: false
# 加密连接密码
password: true
# 数据库连接池配置
pool:
# 初始化连接数
init: 1
# 最小连接数
minIdle: 3
# 最大连接数
maxActive: 20
# 表名前缀
tablePrefix: js_
# # 多数数据源名称列表调用方式DataSourceHolder.setDataSourceName("ds2")
# dataSourceNames: ds2
#
# # 多数据源配置ds2
# ds2:
# type: oracle
# driver: oracle.jdbc.driver.OracleDriver
# url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
# username: jeesite
# password: jeesite
# encryptUsername: false
# encryptPassword: true
# pool:
# init: 1
# minIdle: 3
# maxActive: 20
# Redis 配置
redis:
# Redis 连接参数
host: 127.0.0.1
port: 6379
password: 1234
database: 0
# 定义Key的前缀标识
keyPrefix: jeesite
# Redis 连接池配置
pool:
maxIdle: 3
maxTotal: 20
# Mapper文件刷新线程
mapperRefresh:
enabled: true
delaySeconds: 60
sleepSeconds: 3
mappingPath: mappings
#============================#
#===== System settings ======#
#============================#
#产品信息设置
productName: JeeSite Demo
productVersion: V4.0
copyrightYear: 2018
companyName: ThinkGem
#是否演示模式
demoMode: false
#管理基础路径
adminPath: /a
#前端基础路径
frontPath: /f
#索引页路径
defaultPath: ${adminPath}/login
# 用户相关参数
user:
# 指定超级管理员编号(实施人员,开发团队使用的用户)
superAdminCode: thinkgem
# 超级管理员获取菜单的最小权重默认20>=40二级管理员>=60系统管理员>=80超级管理员
superAdminGetMenuMinWeight: 40
# 系统管理员角色编号(客户方使用的角色,客户方管理员)
corpAdminRoleCode: corpAdmin
# 用户类型配置信息employee员工member会员btype往来单位persion个人expert专家...
# JSON格式说明{"用户类型":{"dao":"Dao的Bean名称","loginView":"登录视图","indexView":"主页框架面视图"}}
userTypeMap: >
{
"employee":{"dao":"employeeDao","loginView":"","indexView":""},
"member":{"dao":"memberDao","loginView":"","indexView":"modules/sys/sysIndexMember"},
"btype":{"dao":"btypeInfoDao","loginView":"","indexView":"modules/sys/sysIndexBtype"},
"persion":{"dao":"persionDao","loginView":"","indexView":"modules/sys/sysIndexPersion"},
"expert":{"dao":"expertDao","loginView":"","indexView":"modules/sys/sysIndexExpert"}
}
# 数据权限设置参数可新增自定义数据权限moduleCode: 针对模块, ctrlPermi: 权限类型, 0全部 1拥有权限 2管理权限
dataScopes: >
[{
moduleCode: "core",
ctrlPermi: "0",
ctrlName: "部门权限",
ctrlType: "Office",
ctrlDataUrl: "/sys/office/treeData",
chkboxType: {"Y":"ps","N":"ps"},
remarks: ""
},{
moduleCode: "core",
ctrlName: "公司权限",
ctrlType: "Company",
ctrlPermi: "0",
ctrlDataUrl: "/sys/company/treeData",
chkboxType: {"Y":"ps","N":"ps"},
remarks: ""
},{
moduleCode: "core",
ctrlName: "角色权限",
ctrlType: "Role",
ctrlPermi: "2",
ctrlDataUrl: "/sys/role/treeData",
chkboxType: {"Y":"ps","N":"ps"},
remarks: ""
}]
# 集团模式多公司、多租户、SAAS模式
useCorpModel: false
# 分页配置
page:
# 分页默认大小
pageSize: 20
# 任务调度
job:
# 是否自动启动任务调度(集群情况下开启一个服务)
autoStartup: true
# 任务调度启动延迟设置(单位:秒)(建议设置项目启动完成后的时间)
startupDelay: 60
# 内容管理
cms:
# 内容管理主站点编码
mainSiteCode: main
#============================#
#==== Framework settings ====#
#============================#
# Shiro 相关配置
shiro:
# 登录相关设置
loginUrl: ${adminPath}/login
logoutUrl: ${shiro.loginUrl}
successUrl: ${adminPath}/index
# CAS 相关配置
casServerUrl: http://192.168.1.3:8080/cas
casClientUrl: http://192.168.1.3:8180/jeesite
# loginUrl: ${shiro.casServerUrl}?service=${shiro.casClientUrl}${adminPath}/login-cas
# logoutUrl: ${shiro.casServerUrl}/logout?service=${shiro.loginUrl}
# successUrl: ${shiro.casClientUrl}
# SSO 登录相关配置
sso:
# 如果启用/sso/{username}/{token}单点登录请修改此安全key并与单点登录系统key一致。
secretKey: abc
# 是否加密单点登录安全Key
encryptKey: true
# 登录提交信息加密
loginSubmit:
# 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔
secretKey: thinkgem,jeesite,com
# 是否允许账号多地登录如果设置为false同一个设备类型的其它地点登录的相同账号被踢下线
isAllowMultiAddrLogin: true
# 是否允许刷新主框架页如果设置为false刷新主页将导致重新登录。如安全性比较高的如银行个人首页不允许刷新。
isAllowRefreshIndex: true
# 是否允许嵌入到外部网站iframe中true不限制false不允许
isAllowExternalSiteIframe: true
# 是否允许跨域访问,如果允许,设置允许的域名,全部域名设置*号,如果不允许,此设置应该为空
# accessControlAllowOrigin: http://demo.jeesite.com
# accessControlAllowOrigin: '*'
# URI 权限过滤器定义
filterChainDefinitions: |
/ReportServer/** = user
${adminPath}/** = user
# filterChainDefinitions: |
# /ReportServer/** = user
# ${adminPath}/file/** = anon
# ${adminPath}/cms/* = anon
# ${adminPath}/cms/site/select = anon
# ${adminPath}/cms/site/* = anon
# ${adminPath}/cms/category/treeData = anon
# ${adminPath}/cms/category/* = anon
# ${adminPath}/cms/article/* = anon
# ${adminPath}/cms/link/* = anon
# ${adminPath}/** = user
# 默认的授权过滤定义如果在filterChainDefinitions中已经定义则该定义会被覆盖。
defaultFilterChainDefinitions: |
/static/** = anon
/userfiles/** = anon
/druid/** = perms[state:druid]
${adminPath}/login-cas = cas
${adminPath}/login = authc
${adminPath}/logout = logout
${adminPath}/file/** = user
${adminPath}/cms/* = perms[cms:view]
${adminPath}/cms/site/select = user
${adminPath}/cms/site/* = perms[cms:site:view]
${adminPath}/cms/category/treeData = user
${adminPath}/cms/category/* = perms[cms:category:view]
${adminPath}/cms/article/* = perms[cms:article:view]
${adminPath}/cms/link/* = perms[cms:link:view]
# Session 相关
session:
#全局会话超时,单位:毫秒, 20m=1200000ms, 30m=1800000ms, 60m=3600000ms, 12h=43200000ms, 1day=86400000ms
sessionTimeout: 1800000
#手机APP设备会话超时参数设置登录请求参数加 param_deviceType=mobileApp 时有效
mobileAppSessionTimeout: 43200000
#定时清理失效会话,清理用户直接关闭浏览器造成的孤立会话
sessionTimeoutClean: 1200000
#会话唯一标识SessionId在Cookie中的名称。
sessionIdCookieName: jeesite.session.id
#共享的SessionId的Cookie名称保存到跟路径下第三方应用获取。同一域名下多个项目时需设置共享Cookie的名称。
shareSessionIdCookieName: jeesite.session.id
# MyBatis 相关
mybatis:
# 扫描基础包设置Aliases、@MyBatisDao如果多个用“,”分隔
scanBasePackage: com.jeesite.modules
# 缓存设置
ehcache:
# 缓存配置文件路径
configFile: cache/ehcache-local.xml
# configFile: cache/ehcache-rmi.xml
# 清理缓存的缓存名称
clearNames: sysCache,userCache,corpCache,cmsCache,pageCachingFilter
# Web 相关
web:
# MVC 视图相关
view:
# 系统主题名称,主题视图优先级最高,如果主题下无这个视图文件则访问默认视图
# 引入页面头部:'/themes/'+themeName+'/include/header.html'
# 引入页面为不:'/themes/'+themeName+'/include/footer.html'
themeName: default
# 静态文件后缀,过滤静态文件,以提高访问性能。
staticFile: .css,.js,.map,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.crx,.xpi,.exe,.ipa,.apk,.otf,.eot,.svg,.ttf,.woff,.woff2
# 静态文件后缀排除的url路径指定哪些uri路径不进行静态文件过滤。
staticFileExcludeUri: /druid/
# 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false
error:
page:
printErrorInfo: true
#============================#
#=== FileUpload settings ====#
#============================#
file:
# 文件上传跟路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径
# baseDir: D:/jeesite
# 上传文件的相对路径支持yyyy, MM, dd, HH, mm, ss, E
uploadPath: '{yyyy}{MM}/'
# 上传单个文件最大字节500M在这之上还有 > Tomcat限制 > Nginx限制等。
maxFileSize: 500*1024*1024
#设置允许上传的文件后缀
imageAllowSuffixes: .gif,.bmp,.jpeg,.jpg,.ico,.png,.tif,.tiff,
mediaAllowSuffixes: .flv,.swf,.mkv,webm,.mid,.mov,.mp3,.mp4,.m4v,.mpc,.mpeg,.mpg,.swf,.wav,.wma,.wmv,.avi,.rm,.rmi,.rmvb,.aiff,.asf,.ogg,.ogv,
fileAllowSuffixes: .doc,.docx,.rtf,.xls,.xlsx,.csv,.ppt,.pptx,.pdf,.vsd,.txt,.md,.xml,.rar,.zip,7z,.tar,.tgz,.jar,.gz,.gzip,.bz2,.cab,.iso,
#允许上传的文件内容类型图片、word、excel、ppt防止修改后缀恶意上传文件默认不启用验证
# allowContentTypes: image/jpeg,image/gif,image/bmp,image/png,image/x-png,
# application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,
# application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
# application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation
#============================#
#===== Message settings =====#
#============================#
msg:
# 是否开启实时发送消息(保存消息后立即检查未读消息并发送),分布式部署下请单独配置消息发送服务,不建议开启此选项。
realtime:
# 是否开启
enabled: true
# 消息发送任务Bean名称
sendTaskBeanName: msgLocalSendTask
# 邮件发送参数
email:
fromAddress: jeesite_demo@163.com
fromPassword: jeesitedemo1234
fromHostName: smtp.163.com
sslOnConnect: false
sslSmtpPort: 994
# 短信网关
sms:
url: http://host:port/msg/sendSms
data: account=demo&pswd=demo&product=
suffix: 【JeeSite】
# 微信相关
weixin:
#微信应用ID
appid: ~
#微信应用密钥
secret: ~
# 微信服务器配置
server:
# 微信服务器配置Token
token: ~
# 微信服务器配置EncodingAESKey
aeskey: ~
# 微信服务器是否开启Debug模式开启后发送未知消息时候会返回消息内容
debug: true
# 微信OAuth登录授权回调地址
oauth:
redirectUri: http://demo.jeesite.com/jeesite
#============================#
#===== Video settings =======#
#============================#
video:
# 视频格式转换 ffmpeg.exe 所放的路径
ffmpegFile: d:/tools/video/ffmpeg-4.9/bin/ffmpeg.exe
# ffmpegFile: d:/tools/video/libav-10.6-win64/bin/avconv.exe
# 视频格式转换 mencoder.exe 所放的路径
mencoderFile: d:/tools/video/mencoder-4.9/mencoder.exe
# 将mp4视频的元数据信息转到视频第一帧
qtFaststartFile: d:/tools/video/qt-faststart/qt-faststart.exe
#============================#
#===== Project settings =====#
#============================#

View File

@@ -5,6 +5,7 @@
<!-- <logger name="org.springframework.jdbc" level="DEBUG" /> -->
<logger name="org.mybatis.spring.transaction" level="DEBUG" />
<logger name="org.apache.catalina.webresources.Cache" level="ERROR" />
<logger name="org.springframework.boot.context.embedded" level="INFO" />
<logger name="com.jeesite" level="DEBUG" />
<logger name="com.jeesite.common.i18n" level="INFO" />

View File

@@ -1,118 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"
default-lazy-init="true">
<description>Shiro Configuration</description>
<!-- Shiro权限过滤过滤器定义 -->
<bean id="shiroFilterChainDefinitionMap" class="com.jeesite.common.shiro.config.FilterChainDefinitionMap">
<!-- 默认的授权过滤定义如果在filterChainDefinitions中已经定义则该定义会被覆盖。-->
<property name="defaultFilterChainDefinitions" value="${shiro.defaultFilterChainDefinitions}"/>
<!-- 自定义的授权过滤器 -->
<property name="filterChainDefinitions" value="${shiro.filterChainDefinitions}"/>
</bean>
<!-- Shiro安全认证过滤器 -->
<bean id="shiroFilter" class="com.jeesite.common.shiro.sso.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="${shiro.loginUrl}" />
<property name="successUrl" value="${shiro.successUrl}" />
<property name="filters">
<map>
<entry key="cas" value-ref="shiroCasFilter" />
<entry key="authc" value-ref="shiroAuthcFilter" />
<entry key="logout" value-ref="shiroLogoutFilter"/>
<entry key="perms" value-ref="shiroPermsFilter"/>
<entry key="roles" value-ref="shiroRolesFilter"/>
<entry key="user" value-ref="shiroUserFilter"/>
</map>
</property>
<property name="filterChainDefinitionMap" ref="shiroFilterChainDefinitionMap"/>
</bean>
<!-- CAS登录过滤器 -->
<bean id="shiroCasFilter" class="com.jeesite.common.shiro.filter.CasAuthenticationFilter">
<property name="authorizingRealm" ref="authorizingRealm"/>
</bean>
<!-- Form登录过滤器 -->
<bean id="shiroAuthcFilter" class="com.jeesite.common.shiro.filter.FormAuthenticationFilter">
<property name="authorizingRealm" ref="authorizingRealm"/>
</bean>
<!-- 登出过滤器 -->
<bean id="shiroLogoutFilter" class="com.jeesite.common.shiro.filter.LogoutFilter"/>
<!-- 权限字符串过滤器 -->
<bean id="shiroPermsFilter" class="com.jeesite.common.shiro.filter.PermissionsAuthorizationFilter"/>
<!-- 角色权限过滤器 -->
<bean id="shiroRolesFilter" class="com.jeesite.common.shiro.filter.RolesAuthorizationFilter"/>
<!-- 用户权限过滤器 -->
<bean id="shiroUserFilter" class="com.jeesite.common.shiro.filter.UserFilter"/>
<!-- 单点登录信息句柄,单点退出用 -->
<bean id="singleSignOutHandler" class="com.jeesite.common.shiro.sso.SingleSignOutHandler"/>
<!-- 系统安全认证实现类 -->
<bean id="authorizingRealm" class="com.jeesite.common.shiro.realm.AuthorizingRealm">
<property name="cachingEnabled" value="false"/>
<property name="sessionDAO" ref="sessionDAO"/>
<property name="userService" ref="userService"/>
<property name="empUserService" ref="empUserService"/>
<property name="singleSignOutHandler" ref="singleSignOutHandler"/>
<property name="casServerUrl" value="${shiro.casServerUrl}"/>
<property name="casServerCallbackUrl" value="${shiro.casClientUrl}${adminPath}/login-cas"/>
</bean>
<!-- 定义Shiro安全管理配置 -->
<bean id="securityManager" class="com.jeesite.common.shiro.mgt.WebSecurityManager">
<property name="realm" ref="authorizingRealm" />
<property name="sessionManager" ref="sessionManager" />
<!-- shiroCacheManager 在spring-context.xml中定义 -->
<property name="cacheManager" ref="shiroCacheManager" />
<!-- 设置支持CAS的subjectFactory -->
<property name="subjectFactory">
<bean class="org.apache.shiro.cas.CasSubjectFactory"/>
</property>
</bean>
<!-- 自定义会话管理配置 -->
<bean id="sessionManager" class="com.jeesite.common.shiro.session.SessionManager">
<!-- sessionDAO 在spring-context.xml中定义 -->
<property name="sessionDAO" ref="sessionDAO"/>
<!-- 会话超时时间,单位:毫秒 -->
<property name="globalSessionTimeout" value="${session.sessionTimeout}"/>
<!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 -->
<property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
<property name="sessionIdCookieEnabled" value="true"/>
</bean>
<!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg name="name" value="${session.sessionIdCookieName}"/>
</bean>
<!-- 支持Shiro对Controller的方法级AOP安全控制 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"
default-lazy-init="true">
<description>Shiro Configuration</description>
<!-- Shiro权限过滤过滤器定义 -->
<bean id="shiroFilterChainDefinitionMap" class="com.jeesite.common.shiro.config.FilterChainDefinitionMap">
<!-- 默认的授权过滤定义如果在filterChainDefinitions中已经定义则该定义会被覆盖。-->
<property name="defaultFilterChainDefinitions" value="${shiro.defaultFilterChainDefinitions}"/>
<!-- 自定义的授权过滤器 -->
<property name="filterChainDefinitions" value="${shiro.filterChainDefinitions}"/>
</bean>
<!-- Shiro安全认证过滤器 -->
<bean id="shiroFilter" class="com.jeesite.common.shiro.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="${shiro.loginUrl}" />
<property name="successUrl" value="${shiro.successUrl}" />
<property name="filters">
<map>
<entry key="cas" value-ref="shiroCasFilter" />
<entry key="authc" value-ref="shiroAuthcFilter" />
<entry key="logout" value-ref="shiroLogoutFilter"/>
<entry key="perms" value-ref="shiroPermsFilter"/>
<entry key="roles" value-ref="shiroRolesFilter"/>
<entry key="user" value-ref="shiroUserFilter"/>
</map>
</property>
<property name="filterChainDefinitionMap" ref="shiroFilterChainDefinitionMap"/>
</bean>
<!-- CAS登录过滤器 -->
<bean id="shiroCasFilter" class="com.jeesite.common.shiro.filter.CasAuthenticationFilter">
<property name="authorizingRealm" ref="authorizingRealm"/>
</bean>
<!-- Form登录过滤器 -->
<bean id="shiroAuthcFilter" class="com.jeesite.common.shiro.filter.FormAuthenticationFilter">
<property name="authorizingRealm" ref="authorizingRealm"/>
</bean>
<!-- 登出过滤器 -->
<bean id="shiroLogoutFilter" class="com.jeesite.common.shiro.filter.LogoutFilter"/>
<!-- 权限字符串过滤器 -->
<bean id="shiroPermsFilter" class="com.jeesite.common.shiro.filter.PermissionsAuthorizationFilter"/>
<!-- 角色权限过滤器 -->
<bean id="shiroRolesFilter" class="com.jeesite.common.shiro.filter.RolesAuthorizationFilter"/>
<!-- 用户权限过滤器 -->
<bean id="shiroUserFilter" class="com.jeesite.common.shiro.filter.UserFilter"/>
<!-- 单点登录信息句柄,单点退出用 -->
<bean id="casOutHandler" class="com.jeesite.common.shiro.cas.CasOutHandler"/>
<!-- 系统安全认证实现类 -->
<bean id="authorizingRealm" class="com.jeesite.common.shiro.realm.AuthorizingRealm">
<property name="cachingEnabled" value="false"/>
<property name="sessionDAO" ref="sessionDAO"/>
<property name="userService" ref="userService"/>
<property name="empUserService" ref="empUserService"/>
<property name="casOutHandler" ref="casOutHandler"/>
<property name="casServerUrl" value="${shiro.casServerUrl}"/>
<property name="casServerCallbackUrl" value="${shiro.casClientUrl}${adminPath}/login-cas"/>
</bean>
<!-- 定义Shiro安全管理配置 -->
<bean id="securityManager" class="com.jeesite.common.shiro.web.WebSecurityManager">
<property name="realm" ref="authorizingRealm" />
<property name="sessionManager" ref="sessionManager" />
<!-- shiroCacheManager 在spring-context.xml中定义 -->
<property name="cacheManager" ref="shiroCacheManager" />
<!-- 设置支持CAS的subjectFactory -->
<property name="subjectFactory">
<bean class="org.apache.shiro.cas.CasSubjectFactory"/>
</property>
</bean>
<!-- 自定义会话管理配置 -->
<bean id="sessionManager" class="com.jeesite.common.shiro.session.SessionManager">
<!-- sessionDAO 在spring-context.xml中定义 -->
<property name="sessionDAO" ref="sessionDAO"/>
<!-- 从URL中去掉JSESSIONID串 -->
<property name="sessionIdUrlRewritingEnabled" value="false" />
<!-- 会话超时时间,单位:毫秒 -->
<property name="globalSessionTimeout" value="${session.sessionTimeout}"/>
<!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 -->
<property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
<property name="sessionIdCookieEnabled" value="true"/>
</bean>
<!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg name="name" value="${session.sessionIdCookieName}"/>
</bean>
<!-- 支持Shiro对Controller的方法级AOP安全控制 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
</beans>

View File

@@ -1,116 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<description>Spring MVC Configuration</description>
<!-- 加载配置属性文件谁先加载谁优先级越高jeesite.yml的优先级高于jeesite-core.yml-->
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources">
<array><value>classpath:jeesite-core.yml</value>
<value>classpath:jeesite.yml</value></array>
</property>
</bean>
<context:property-placeholder properties-ref="yamlProperties" ignore-unresolvable="true"/>
<!-- 默认的注解映射的支持org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" validator="beanValidator">
<mvc:message-converters register-defaults="true">
<!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
<!-- 将Jackson2HttpMessageConverter的默认格式化输出为false -->
<bean class="com.jeesite.common.web.converter.JsonHttpMessageConverter">
<property name="prettyPrint" value="false"/>
</bean>
<!-- 将Jackson2XmlHttpMessageConverter的默认格式化输出为false -->
<bean class="com.jeesite.common.web.converter.XmlHttpMessageConverter">
<property name="prettyPrint" value="false"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- REST中根据URL后缀自动判定Content-Type及相应的View -->
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes" >
<value>
json=application/json
xml=application/xml
</value>
</property>
<property name="ignoreAcceptHeader" value="true"/><!-- 忽略accept-header匹配不加后缀使用默认配置 -->
<property name="favorPathExtension" value="true"/><!-- .json、.xml后缀匹配 -->
<property name="favorParameter" value="false"/><!-- format参数名匹配 -->
</bean>
<!-- 定义视图文件解析 -->
<mvc:view-resolvers>
<!-- Beetl主题视图解析器order越小优先级越高 -->
<bean name="viewResolverBeetlThemes" class="com.jeesite.common.beetl.view.BeetlViewResolver">
<property name="prefix" value="/themes/${web.view.themeName}/"/>
<property name="suffix" value=".html" />
<property name="order" value="1000" />
</bean>
<!-- Beetl默认视图文件解析order越小优先级越高 -->
<bean name="viewResolverBeetlDefault" class="com.jeesite.common.beetl.view.BeetlViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".html" />
<property name="order" value="2000" />
</bean>
<!-- JSP主题视图文件解析order越小优先级越高 -->
<bean id="viewResolverJspThemes" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="com.jeesite.common.web.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/themes/${web.view.themeName}/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="10000"/>
</bean>
<!-- JSP视图文件解析 order越小优先级越高-->
<bean id="viewResolverJspDefault" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="com.jeesite.common.web.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="20000"/>
</bean>
<!-- 默认视图定义,根据后缀渲染 -->
<mvc:content-negotiation>
<mvc:default-views>
<bean class="com.jeesite.common.web.view.JsonView">
<property name="prettyPrint" value="false"/>
</bean>
<bean class="com.jeesite.common.web.view.XmlView">
<property name="prettyPrint" value="false"/>
</bean>
</mvc:default-views>
</mvc:content-negotiation>
</mvc:view-resolvers>
<!-- 直接访问项目名称跳转到默认地址 -->
<mvc:view-controller path="/" view-name="redirect:${defaultPath}"/>
<!-- 静态资源映射可读取classes下、jar包里的静态文件 -->
<mvc:resources mapping="/static/**" location="/static/,classpath:/static/" cache-period="31536000"/>
<!-- 对静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 -->
<mvc:default-servlet-handler/>
<!-- 异常拦截处理异常信息其它异常拦截见BaseController里的@ExceptionHandler注解 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthenticatedException">error/403</prop>
<prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
<prop key="java.lang.Throwable">error/500</prop>
</props>
</property>
</bean>
<!-- Spring MVC上传文件 MultipartFile 拦截,设置字符集 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8" />
</bean>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<description>Spring MVC Configuration</description>
<!-- 加载配置属性文件谁先加载谁优先级越高jeesite.yml的优先级高于jeesite-core.yml-->
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources">
<array><value>classpath:jeesite-core.yml</value>
<value>classpath:jeesite.yml</value></array>
</property>
</bean>
<context:property-placeholder properties-ref="yamlProperties" ignore-unresolvable="true"/>
<!-- 默认的注解映射的支持org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" validator="beanValidator">
<mvc:message-converters register-defaults="true">
<!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
<!-- 将Jackson2HttpMessageConverter的默认格式化输出为false -->
<bean class="com.jeesite.common.web.converter.JsonHttpMessageConverter">
<property name="prettyPrint" value="false"/>
</bean>
<!-- 将Jackson2XmlHttpMessageConverter的默认格式化输出为false -->
<bean class="com.jeesite.common.web.converter.XmlHttpMessageConverter">
<property name="prettyPrint" value="false"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- REST中根据MediaType自动判定Content-Type及相应的View -->
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes" >
<value>
json=application/json
xml=application/xml
</value>
</property>
<property name="ignoreAcceptHeader" value="true"/><!-- 忽略accept-header匹配不加后缀使用默认配置 -->
<property name="favorPathExtension" value="true"/><!-- .json、.xml后缀匹配 -->
<property name="favorParameter" value="false"/><!-- format参数名匹配 -->
</bean>
<!-- 定义视图文件解析 -->
<mvc:view-resolvers>
<!-- Beetl主题视图解析器order越小优先级越高 -->
<bean name="viewResolverBeetlThemes" class="com.jeesite.common.beetl.view.BeetlViewResolver">
<property name="prefix" value="/themes/${web.view.themeName}/"/>
<property name="suffix" value=".html" />
<property name="order" value="1000" />
</bean>
<!-- Beetl默认视图文件解析order越小优先级越高 -->
<bean name="viewResolverBeetlDefault" class="com.jeesite.common.beetl.view.BeetlViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".html" />
<property name="order" value="2000" />
</bean>
<!-- JSP主题视图文件解析order越小优先级越高 -->
<bean id="viewResolverJspThemes" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="com.jeesite.common.web.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/themes/${web.view.themeName}/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="10000"/>
</bean>
<!-- JSP视图文件解析 order越小优先级越高-->
<bean id="viewResolverJspDefault" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="com.jeesite.common.web.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="20000"/>
</bean>
<!-- 默认视图定义,根据后缀渲染 -->
<mvc:content-negotiation>
<mvc:default-views>
<bean class="com.jeesite.common.web.view.JsonView">
<property name="prettyPrint" value="false"/>
</bean>
<bean class="com.jeesite.common.web.view.XmlView">
<property name="prettyPrint" value="false"/>
</bean>
</mvc:default-views>
</mvc:content-negotiation>
</mvc:view-resolvers>
<!-- 静态资源映射可读取classes下、jar包里的静态文件 -->
<mvc:resources mapping="/static/**" location="/static/,classpath:/static/" cache-period="31536000"/>
<!-- 静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 -->
<mvc:default-servlet-handler/>
<!-- 异常拦截处理异常信息其它异常拦截见BaseController里的@ExceptionHandler注解 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthenticatedException">error/403</prop>
<prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
<prop key="java.lang.Throwable">error/500</prop>
</props>
</property>
</bean>
<!-- Spring MVC上传文件 MultipartFile 拦截,设置字符集 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8" />
</bean>
</beans>