From 1809f133ada8949cabca0caa360660f707c66323 Mon Sep 17 00:00:00 2001
From: jinxiaojie <15736965205@163.com>
Date: Wed, 11 Nov 2020 14:59:44 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4shiro-token=E5=88=86=E6=94=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 80 +++---
.../fc/test/controller/AdminController.java | 261 +++++++++---------
.../test/controller/admin/ApiController.java | 4 +-
.../test/controller/admin/ApiController2.java | 32 +++
.../com/fc/test/shiro/config/ShiroConfig.java | 130 ++++++---
.../shiro/config/ShiroFilterMapFactory.java | 67 ++---
.../service/CORSAuthenticationFilter.java | 57 ++++
.../fc/test/shiro/service/ShiroSession.java | 69 +++++
.../shiro/service/UuidSessionIdGenerator.java | 18 ++
9 files changed, 473 insertions(+), 245 deletions(-)
create mode 100644 src/main/java/com/fc/test/controller/admin/ApiController2.java
create mode 100644 src/main/java/com/fc/test/shiro/service/CORSAuthenticationFilter.java
create mode 100644 src/main/java/com/fc/test/shiro/service/ShiroSession.java
create mode 100644 src/main/java/com/fc/test/shiro/service/UuidSessionIdGenerator.java
diff --git a/pom.xml b/pom.xml
index 1c21ccc..9612fff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,5 +1,6 @@
-
4.0.0
@@ -23,7 +24,7 @@
1.3.3
2.5
-
+
@@ -45,15 +46,15 @@
- io.springfox
- springfox-swagger2
- 2.9.2
-
-
- io.springfox
- springfox-swagger-ui
- 2.9.2
-
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
+
+ io.springfox
+ springfox-swagger-ui
+ 2.9.2
+
com.google.code.gson
@@ -65,20 +66,17 @@
pagehelper-spring-boot-starter
1.2.5
-
+
+
+
mysql
mysql-connector-java
-
-
-
-
+
+
+
com.alibaba
@@ -155,12 +153,12 @@
- org.apache.velocity
- velocity
- 1.7
+ org.apache.velocity
+ velocity
+ 1.7
-
+
org.springframework.boot
spring-boot-starter-websocket
@@ -176,14 +174,14 @@
spring-boot-configuration-processor
true
-
+
- javax.mail
- mail
- 1.4.7
+ javax.mail
+ mail
+ 1.4.7
-
+
org.json
@@ -191,13 +189,14 @@
20180813
- ueditor
- 1.4.3
+ ueditor
+ 1.4.3
1.8
system
${basedir}/lib/ueditor-1.1.2.jar
-
+
+
org.quartz-scheduler
quartz
@@ -208,7 +207,12 @@
qiniu-java-sdk
[7.2.0, 7.2.99]
-
+
+
+ com.alibaba
+ fastjson
+ 1.2.68
+
@@ -220,13 +224,13 @@
org.apache.maven.plugins
- maven-surefire-plugin
-
+ maven-surefire-plugin
+
true
-
+
org.mybatis.generator
mybatis-generator-maven-plugin
@@ -280,6 +284,6 @@
-
+
diff --git a/src/main/java/com/fc/test/controller/AdminController.java b/src/main/java/com/fc/test/controller/AdminController.java
index d4a22df..a1c4821 100644
--- a/src/main/java/com/fc/test/controller/AdminController.java
+++ b/src/main/java/com/fc/test/controller/AdminController.java
@@ -35,6 +35,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
/**
* 后台方法
+ *
* @ClassName: HomeController
* @author fuce
* @date 2019-10-21 00:10
@@ -42,57 +43,60 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
*/
@Controller
@RequestMapping("/admin")
-public class AdminController extends BaseController{
- private static Logger logger=LoggerFactory.getLogger(AdminController.class);
-
+public class AdminController extends BaseController {
+ private static Logger logger = LoggerFactory.getLogger(AdminController.class);
+
private String prefix = "admin";
-
- @ApiOperation(value="首页",notes="首页")
+
+ @ApiOperation(value = "首页", notes = "首页")
@GetMapping("/index")
public String index(HttpServletRequest request) {
- //获取菜单栏
- BootstrapTree bootstrapTree= sysPermissionService.getbooBootstrapTreePerm(ShiroUtils.getUserId());
- request.getSession().setAttribute("bootstrapTree", bootstrapTree);
- request.getSession().setAttribute("sessionUserName",ShiroUtils.getUser().getNickname());
- //获取公告信息
- List notices=sysNoticeService.getuserNoticeNotRead(ShiroUtils.getUser(),0);
- request.getSession().setAttribute("notices",notices);
- return prefix+"/index";
+ // 获取菜单栏
+ BootstrapTree bootstrapTree = sysPermissionService.getbooBootstrapTreePerm(ShiroUtils.getUserId());
+ request.getSession().setAttribute("bootstrapTree", bootstrapTree);
+ request.getSession().setAttribute("sessionUserName", ShiroUtils.getUser().getNickname());
+ // 获取公告信息
+ List notices = sysNoticeService.getuserNoticeNotRead(ShiroUtils.getUser(), 0);
+ request.getSession().setAttribute("notices", notices);
+ return prefix + "/index";
}
-
- @ApiOperation(value="局部刷新区域",notes="局部刷新区域")
+
+ @ApiOperation(value = "局部刷新区域", notes = "局部刷新区域")
@GetMapping("/main")
public String main(ModelMap map) {
- setTitle(map, new TitleVo("首页", "首页", true,"欢迎进入", true, false));
- return prefix+"/main";
+ setTitle(map, new TitleVo("首页", "首页", true, "欢迎进入", true, false));
+ return prefix + "/main";
}
-
+
/**
* 请求到登陆界面
+ *
* @param request
* @return
*/
- @ApiOperation(value="请求到登陆界面",notes="请求到登陆界面")
+ @ApiOperation(value = "请求到登陆界面", notes = "请求到登陆界面")
@GetMapping("/login")
- public String login(ModelMap modelMap) {
- try {
- if ((null != SecurityUtils.getSubject() && SecurityUtils.getSubject().isAuthenticated()) || SecurityUtils.getSubject().isRemembered()) {
- return "redirect:/"+prefix+"/index";
- } else {
- System.out.println("--进行登录验证..验证开始");
-
- modelMap.put("RollVerification", V2Config.getRollVerification());
- System.out.println("V2Config.getRollVerification()>>>"+V2Config.getRollVerification());
- return "login";
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "login";
- }
-
+ public String login(ModelMap modelMap) {
+ try {
+ if ((null != SecurityUtils.getSubject() && SecurityUtils.getSubject().isAuthenticated())
+ || SecurityUtils.getSubject().isRemembered()) {
+ return "redirect:/" + prefix + "/index";
+ } else {
+ System.out.println("--进行登录验证..验证开始");
+
+ modelMap.put("RollVerification", V2Config.getRollVerification());
+ System.out.println("V2Config.getRollVerification()>>>" + V2Config.getRollVerification());
+ return "login";
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "login";
+ }
+
/**
* 用户登陆验证
+ *
* @param user
* @param rcode
* @param redirectAttributes
@@ -101,122 +105,123 @@ public class AdminController extends BaseController{
* @param request
* @return
*/
- @ApiOperation(value="用户登陆验证",notes="用户登陆验证")
+ @ApiOperation(value = "用户登陆验证", notes = "用户登陆验证")
@PostMapping("/login")
@ResponseBody
- public AjaxResult login(TsysUser user,String code,RedirectAttributes redirectAttributes,boolean rememberMe,HttpServletRequest request) {
- //ModelAndView view =new ModelAndView();
- Boolean yz=false;
- if(V2Config.getRollVerification()) {//滚动验证
- yz=true;
- }else {//图片验证
- String scode = (String)request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
- yz=StringUtils.isNotEmpty(scode)&&StringUtils.isNotEmpty(code)&&scode.equals(code);
+ public AjaxResult login(TsysUser user, String code, RedirectAttributes redirectAttributes, boolean rememberMe,
+ HttpServletRequest request) {
+ // ModelAndView view =new ModelAndView();
+ Boolean yz = false;
+ if (V2Config.getRollVerification()) {// 滚动验证
+ yz = true;
+ } else {// 图片验证
+ String scode = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
+ yz = StringUtils.isNotEmpty(scode) && StringUtils.isNotEmpty(code) && scode.equals(code);
}
- //判断验证码
- if(yz){
- String userName = user.getUsername();
- Subject currentUser = SecurityUtils.getSubject();
- //是否验证通过
- if(!currentUser.isAuthenticated()) {
- UsernamePasswordToken token =new UsernamePasswordToken(userName,user.getPassword());
- try {
- if(rememberMe) {
- token.setRememberMe(true);
- }
- //存入用户
- currentUser.login(token);
- if(StringUtils.isNotNull(ShiroUtils.getUser())) {
- //跳转到 get请求的登陆方法
- //view.setViewName("redirect:/"+prefix+"/index");
- return AjaxResult.success();
- }else {
- return AjaxResult.error(500,"未知账户");
- }
- }catch (UnknownAccountException uae) {
- logger.info("对用户[" + userName + "]进行登录验证..验证未通过,未知账户");
- return AjaxResult.error(500,"未知账户");
- } catch (IncorrectCredentialsException ice) {
- logger.info("对用户[" + userName + "]进行登录验证..验证未通过,错误的凭证");
- return AjaxResult.error(500, "用户名或密码不正确");
- } catch (LockedAccountException lae) {
- logger.info("对用户[" + userName + "]进行登录验证..验证未通过,账户已锁定");
- return AjaxResult.error(500,"账户已锁定");
- } catch (ExcessiveAttemptsException eae) {
- logger.info("对用户[" + userName + "]进行登录验证..验证未通过,错误次数过多");
- return AjaxResult.error(500,"用户名或密码错误次数过多");
- } catch (AuthenticationException ae) {
- //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
- logger.info("对用户[" + userName + "]进行登录验证..验证未通过,堆栈轨迹如下");
- ae.printStackTrace();
- return AjaxResult.error(500,"用户名或密码不正确");
- }
- }else {
- if(StringUtils.isNotNull(ShiroUtils.getUser())) {
- //跳转到 get请求的登陆方法
- //view.setViewName("redirect:/"+prefix+"/index");
- return AjaxResult.success();
- }else {
- return AjaxResult.error(500,"未知账户");
- }
- }
- }else{
- return AjaxResult.error(500,"验证码不正确!");
- }
-
+ // 判断验证码
+ if (yz) {
+ String userName = user.getUsername();
+ Subject currentUser = SecurityUtils.getSubject();
+ // 是否验证通过
+ if (!currentUser.isAuthenticated()) {
+ UsernamePasswordToken token = new UsernamePasswordToken(userName, user.getPassword());
+ try {
+ if (rememberMe) {
+ token.setRememberMe(true);
+ }
+ // 存入用户
+ currentUser.login(token);
+ if (StringUtils.isNotNull(ShiroUtils.getUser())) {
+ // 若为前后端分离版本,则可把sessionId返回,作为分离版本的请求头authToken
+ // String authToken = ShiroUtils.getSessionId();
+ // return AjaxResult.successData(200, authToken);
+ return AjaxResult.success();
+ } else {
+ return AjaxResult.error(500, "未知账户");
+ }
+ } catch (UnknownAccountException uae) {
+ logger.info("对用户[" + userName + "]进行登录验证..验证未通过,未知账户");
+ return AjaxResult.error(500, "未知账户");
+ } catch (IncorrectCredentialsException ice) {
+ logger.info("对用户[" + userName + "]进行登录验证..验证未通过,错误的凭证");
+ return AjaxResult.error(500, "用户名或密码不正确");
+ } catch (LockedAccountException lae) {
+ logger.info("对用户[" + userName + "]进行登录验证..验证未通过,账户已锁定");
+ return AjaxResult.error(500, "账户已锁定");
+ } catch (ExcessiveAttemptsException eae) {
+ logger.info("对用户[" + userName + "]进行登录验证..验证未通过,错误次数过多");
+ return AjaxResult.error(500, "用户名或密码错误次数过多");
+ } catch (AuthenticationException ae) {
+ // 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
+ logger.info("对用户[" + userName + "]进行登录验证..验证未通过,堆栈轨迹如下");
+ ae.printStackTrace();
+ return AjaxResult.error(500, "用户名或密码不正确");
+ }
+ } else {
+ if (StringUtils.isNotNull(ShiroUtils.getUser())) {
+ // 跳转到 get请求的登陆方法
+ // view.setViewName("redirect:/"+prefix+"/index");
+ return AjaxResult.success();
+ } else {
+ return AjaxResult.error(500, "未知账户");
+ }
+ }
+ } else {
+ return AjaxResult.error(500, "验证码不正确!");
+ }
+
}
-
+
/**
* 退出登陆
+ *
* @return
*/
- @ApiOperation(value="退出登陆",notes="退出登陆")
+ @ApiOperation(value = "退出登陆", notes = "退出登陆")
@GetMapping("/Loginout")
- public String LoginOut(HttpServletRequest request, HttpServletResponse response){
- //在这里执行退出系统前需要清空的数据
+ public String LoginOut(HttpServletRequest request, HttpServletResponse response) {
+ // 在这里执行退出系统前需要清空的数据
Subject subject = SecurityUtils.getSubject();
- //注销
- subject.logout();
- return "redirect:/"+prefix+"/login";
+ // 注销
+ subject.logout();
+ return "redirect:/" + prefix + "/login";
}
-
-
-
-
- /****页面测试****/
- @ApiOperation(value="404页面",notes="404页面")
+
+ /**** 页面测试 ****/
+ @ApiOperation(value = "404页面", notes = "404页面")
@GetMapping("Out404")
- public String Out404(HttpServletRequest request, HttpServletResponse response){
-
- return "redirect:/error/404";
+ public String Out404(HttpServletRequest request, HttpServletResponse response) {
+
+ return "redirect:/error/404";
}
-
+
@GetMapping("Out403")
- @ApiOperation(value="403页面",notes="403页面")
- public String Out403(HttpServletRequest request, HttpServletResponse response){
-
- return "redirect:/error/403";
+ @ApiOperation(value = "403页面", notes = "403页面")
+ public String Out403(HttpServletRequest request, HttpServletResponse response) {
+
+ return "redirect:/error/403";
}
-
- @ApiOperation(value="500页面",notes="500页面")
+
+ @ApiOperation(value = "500页面", notes = "500页面")
@GetMapping("Out500")
- public String Out500(HttpServletRequest request, HttpServletResponse response){
-
- return "redirect:/error/500";
+ public String Out500(HttpServletRequest request, HttpServletResponse response) {
+
+ return "redirect:/error/500";
}
-
+
/**
* 权限测试跳转页面
+ *
* @param request
* @param response
* @return
*/
- @ApiOperation(value="权限测试跳转页面",notes="权限测试跳转页面")
+ @ApiOperation(value = "权限测试跳转页面", notes = "权限测试跳转页面")
@GetMapping("Outqx")
@RequiresPermissions("system:user:asd")
- public String Outqx(HttpServletRequest request, HttpServletResponse response){
-
- return "redirect:/error/500";
+ public String Outqx(HttpServletRequest request, HttpServletResponse response) {
+
+ return "redirect:/error/500";
}
- /****页面测试EDN****/
+ /**** 页面测试EDN ****/
}
diff --git a/src/main/java/com/fc/test/controller/admin/ApiController.java b/src/main/java/com/fc/test/controller/admin/ApiController.java
index 5789452..a724839 100644
--- a/src/main/java/com/fc/test/controller/admin/ApiController.java
+++ b/src/main/java/com/fc/test/controller/admin/ApiController.java
@@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fc.test.common.domain.AjaxResult;
+import com.fc.test.shiro.util.ShiroUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -26,7 +27,6 @@ public class ApiController {
@GetMapping("/test")
@ResponseBody
public AjaxResult test() {
-
- return AjaxResult.success();
+ return AjaxResult.successData(200, ShiroUtils.getLoginName());
}
}
diff --git a/src/main/java/com/fc/test/controller/admin/ApiController2.java b/src/main/java/com/fc/test/controller/admin/ApiController2.java
new file mode 100644
index 0000000..babfe11
--- /dev/null
+++ b/src/main/java/com/fc/test/controller/admin/ApiController2.java
@@ -0,0 +1,32 @@
+package com.fc.test.controller.admin;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import com.fc.test.common.domain.AjaxResult;
+import com.fc.test.shiro.util.ShiroUtils;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 该接口为了前后端分离or手机端服务不用登录的接口 访问地址:localhot:8080/ApiController/test
+ * 如何还需要其他 接口不登陆就能访问:ShiroFilterMapFactory.java里面配置开放自己的controller
+ * @ClassName: ApiController
+ * @author fuce
+ * @date 2020-04-15 22:59
+ */
+@Api(value = "api_test")
+@Controller
+@RequestMapping("/api")
+public class ApiController2 {
+
+ //@Log(title = "${TsysTables.tableComment}集合查询", action = "111")
+ @ApiOperation(value = "测试方法", notes = "测试方法")
+ @GetMapping("/test")
+ @ResponseBody
+ public AjaxResult test() {
+ return AjaxResult.successData(200, ShiroUtils.getLoginName());
+ }
+}
diff --git a/src/main/java/com/fc/test/shiro/config/ShiroConfig.java b/src/main/java/com/fc/test/shiro/config/ShiroConfig.java
index 10ed1f9..b50675e 100644
--- a/src/main/java/com/fc/test/shiro/config/ShiroConfig.java
+++ b/src/main/java/com/fc/test/shiro/config/ShiroConfig.java
@@ -1,26 +1,38 @@
package com.fc.test.shiro.config;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.servlet.Filter;
+
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
-import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.aspectj.weaver.NewConstructorTypeMunger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+
+import com.fc.test.shiro.service.CORSAuthenticationFilter;
import com.fc.test.shiro.service.MyShiroRealm;
-import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
+import com.fc.test.shiro.service.ShiroSession;
+import com.fc.test.shiro.service.UuidSessionIdGenerator;
+import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
/**
* 权限配置文件
+ *
* @ClassName: ShiroConfiguration
* @author fuce
* @date 2018年8月25日
@@ -31,122 +43,152 @@ public class ShiroConfig {
/**
* 这是shiro的大管家,相当于mybatis里的SqlSessionFactoryBean
+ *
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
- //登录
+ shiroFilterFactoryBean.setSecurityManager(securityManager);
+ // 登录
shiroFilterFactoryBean.setLoginUrl("/admin/login");
- //首页
- shiroFilterFactoryBean.setSuccessUrl("/");
- //错误页面,认证不通过跳转
+ // 首页
+// shiroFilterFactoryBean.setSuccessUrl("/");
+ // 错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
- //页面权限控制
+ // 页面权限控制
shiroFilterFactoryBean.setFilterChainDefinitionMap(ShiroFilterMapFactory.shiroFilterMap());
- shiroFilterFactoryBean.setSecurityManager(securityManager);
+ // 自定义拦截器
+ Map customFilterMap = new LinkedHashMap<>();
+ customFilterMap.put("corsAuthenticationFilter", new CORSAuthenticationFilter());
+ shiroFilterFactoryBean.setFilters(customFilterMap);
+
return shiroFilterFactoryBean;
}
-
+
/**
* web应用管理配置
+ *
* @param shiroRealm
* @param cacheManager
* @param manager
* @return
*/
@Bean
- public DefaultWebSecurityManager securityManager(Realm shiroRealm,CacheManager cacheManager,RememberMeManager manager) {
+ public DefaultWebSecurityManager securityManager(Realm shiroRealm, CacheManager cacheManager,
+ RememberMeManager manager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setCacheManager(cacheManager);
- securityManager.setRememberMeManager(manager);//记住Cookie
+ securityManager.setRememberMeManager(manager);// 记住Cookie
securityManager.setRealm(shiroRealm);
securityManager.setSessionManager(sessionManager());
return securityManager;
}
+// /**
+// * session过期控制
+// * @return
+// * @author fuce
+// * @Date 2019年11月2日 下午12:49:49
+// */
+// @Bean
+// public DefaultWebSessionManager sessionManager() {
+// DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
+// // 设置session过期时间3600s
+// Long timeout=60L*1000*60;//毫秒级别
+// defaultWebSessionManager.setGlobalSessionTimeout(timeout);
+// return defaultWebSessionManager;
+// }
+
/**
- * session过期控制
+ * 自定义的 shiro session 缓存管理器,用于跨域等情况下使用 token 进行验证,不依赖于sessionId
+ *
* @return
- * @author fuce
- * @Date 2019年11月2日 下午12:49:49
*/
@Bean
- public DefaultWebSessionManager sessionManager() {
- DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
- // 设置session过期时间3600s
- Long timeout=60L*1000*60;//毫秒级别
- defaultWebSessionManager.setGlobalSessionTimeout(timeout);
- return defaultWebSessionManager;
+ public SessionManager sessionManager() {
+ // 将我们继承后重写的shiro session 注册
+ ShiroSession shiroSession = new ShiroSession();
+ // 如果后续考虑多tomcat部署应用,可以使用shiro-redis开源插件来做session 的控制,或者nginx 的负载均衡
+ EnterpriseCacheSessionDAO sessionDAO = new EnterpriseCacheSessionDAO();
+ sessionDAO.setSessionIdGenerator(new UuidSessionIdGenerator());
+ shiroSession.setSessionDAO(sessionDAO);
+ return shiroSession;
}
+
/**
* 加密算法
+ *
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
- hashedCredentialsMatcher.setHashAlgorithmName("MD5");//采用MD5 进行加密
- hashedCredentialsMatcher.setHashIterations(1);//加密次数
+ hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 采用MD5 进行加密
+ hashedCredentialsMatcher.setHashIterations(1);// 加密次数
return hashedCredentialsMatcher;
}
-
+
/**
* 记住我的配置
+ *
* @return
*/
@Bean
public RememberMeManager rememberMeManager() {
Cookie cookie = new SimpleCookie("rememberMe");
- cookie.setHttpOnly(true);//通过js脚本将无法读取到cookie信息
- cookie.setMaxAge(60 * 60 * 24);//cookie保存一天
- CookieRememberMeManager manager=new CookieRememberMeManager();
+ cookie.setHttpOnly(true);// 通过js脚本将无法读取到cookie信息
+ cookie.setMaxAge(60 * 60 * 24);// cookie保存一天
+ CookieRememberMeManager manager = new CookieRememberMeManager();
manager.setCookie(cookie);
return manager;
}
+
/**
* 缓存配置
+ *
* @return
*/
@Bean
public CacheManager cacheManager() {
- MemoryConstrainedCacheManager cacheManager=new MemoryConstrainedCacheManager();//使用内存缓存
+ MemoryConstrainedCacheManager cacheManager = new MemoryConstrainedCacheManager();// 使用内存缓存
return cacheManager;
}
-
+
/**
* 配置realm,用于认证和授权
+ *
* @param hashedCredentialsMatcher
* @return
*/
@Bean
public AuthorizingRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
MyShiroRealm shiroRealm = new MyShiroRealm();
- //校验密码用到的算法
+ // 校验密码用到的算法
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return shiroRealm;
}
-
+
/**
* 启用shiro方言,这样能在页面上使用shiro标签
+ *
* @return
*/
@Bean
- public ShiroDialect shiroDialect() {
- return new ShiroDialect();
- }
-
+ public ShiroDialect shiroDialect() {
+ return new ShiroDialect();
+ }
+
/**
- * 启用shiro注解
- *加入注解的使用,不加入这个注解不生效
- */
- @Bean
- public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
- AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
- advisor.setSecurityManager(securityManager);
- return advisor;
- }
-
+ * 启用shiro注解 加入注解的使用,不加入这个注解不生效
+ */
+ @Bean
+ public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(
+ org.apache.shiro.mgt.SecurityManager securityManager) {
+ AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
+ advisor.setSecurityManager(securityManager);
+ return advisor;
+ }
}
diff --git a/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java b/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java
index 5670d76..674b35e 100644
--- a/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java
+++ b/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java
@@ -10,54 +10,55 @@ import java.util.Map;
*
*/
public class ShiroFilterMapFactory {
-
-/**
-anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
-
-authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
-
-roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
-
-perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
-
-rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
-
-port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
-是你访问的url里的?后面的参数。
+ /**
+ * anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
+ *
+ * authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
+ *
+ * roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
+ *
+ * perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
+ *
+ * rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method]
+ * ,其中method为post,get,delete等。
+ *
+ * port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
+ *
+ * 是你访问的url里的?后面的参数。
+ *
+ * authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
+ *
+ * ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
+ *
+ * user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
+ *
+ */
-authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
-
-ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
-
-user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
-
-*/
-
public static Map shiroFilterMap() {
// 设置路径映射,注意这里要用LinkedHashMap 保证有序
LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>();
- //对所有用户认证
+ // 对所有用户认证
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/admin/login", "anon");
filterChainDefinitionMap.put("/admin/logout", "logout");
- //放验证码
+ // 放验证码
filterChainDefinitionMap.put("/captcha/**", "anon");
// 释放 druid 监控画面
filterChainDefinitionMap.put("/druid/**", "anon");
- //释放websocket请求
+ // 释放websocket请求
filterChainDefinitionMap.put("/websocket", "anon");
- //前端
+ // 前端
filterChainDefinitionMap.put("/", "anon");
- filterChainDefinitionMap.put("/index", "anon");//任务调度暂时放开
-
+ filterChainDefinitionMap.put("/index", "anon");// 任务调度暂时放开
+
filterChainDefinitionMap.put("/quartz/**", "anon");
-
- //开放APicontroller
+
+ // 开放APicontroller
filterChainDefinitionMap.put("/ApiController/**", "anon");
-
- //对所有页面进行认证
- filterChainDefinitionMap.put("/**","authc");
+
+ // 对所有页面进行认证
+ filterChainDefinitionMap.put("/**", "authc");
return filterChainDefinitionMap;
}
}
diff --git a/src/main/java/com/fc/test/shiro/service/CORSAuthenticationFilter.java b/src/main/java/com/fc/test/shiro/service/CORSAuthenticationFilter.java
new file mode 100644
index 0000000..a450f26
--- /dev/null
+++ b/src/main/java/com/fc/test/shiro/service/CORSAuthenticationFilter.java
@@ -0,0 +1,57 @@
+package com.fc.test.shiro.service;
+
+import java.io.PrintWriter;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
+
+import com.alibaba.fastjson.JSON;
+import com.fc.test.common.domain.AjaxResult;
+
+/**
+ * @author :LX
+ * 创建时间: 2019/5/31. 10:25
+ * 地点:广州
+ * 目的: 过滤OPTIONS请求 继承shiro 的form表单过滤器,对
+ * OPTIONS 请求进行过滤。 前后端分离项目中,由于跨域,会导致复杂请求,即会发送preflighted
+ * request,这样会导致在GET/POST等请求之前会先发一个OPTIONS请求,但OPTIONS请求并不带shiro
+ * 的'authToken'字段(shiro的SessionId),即OPTIONS请求不能通过shiro验证,会返回未认证的信息。
+ *
+ *备注说明: 需要在 shiroConfig 进行注册
+ */
+public class CORSAuthenticationFilter extends FormAuthenticationFilter {
+
+ /**
+ * 直接过滤可以访问的请求类型
+ */
+ private static final String REQUET_TYPE = "OPTIONS";
+
+ public CORSAuthenticationFilter() {
+ super();
+ }
+
+ @Override
+ public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+ if (((HttpServletRequest) request).getMethod().toUpperCase().equals(REQUET_TYPE)) {
+ return true;
+ }
+ return super.isAccessAllowed(request, response, mappedValue);
+ }
+
+ @Override
+ protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+ HttpServletResponse res = (HttpServletResponse) response;
+ res.setHeader("Access-Control-Allow-Origin", "*");
+ res.setStatus(HttpServletResponse.SC_OK);
+ res.setCharacterEncoding("UTF-8");
+ PrintWriter writer = res.getWriter();
+// ResultJson resultJson = new ResultJson(Constant.ERROR_CODE_NO_LOGIN, ResultEnum.ERROR.getStatus(), "请先登录系统!", null);
+ writer.write(JSON.toJSONString(AjaxResult.error(500, "请先登录系统!")));
+ writer.close();
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fc/test/shiro/service/ShiroSession.java b/src/main/java/com/fc/test/shiro/service/ShiroSession.java
new file mode 100644
index 0000000..a7b618f
--- /dev/null
+++ b/src/main/java/com/fc/test/shiro/service/ShiroSession.java
@@ -0,0 +1,69 @@
+package com.fc.test.shiro.service;
+
+import java.io.Serializable;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * 原文链接:https://my.oschina.net/sprouting/blog/3059282
+ *
+ * @author :LX
+ * 创建时间: 2019/5/30. 18:08
+ * 地点:广州
+ * 目的: shiro 的 session 管理
+ * 自定义session规则,实现前后分离,在跨域等情况下使用token 方式进行登录验证才需要,否则没必须使用本类。 shiro默认使用
+ * ServletContainerSessionManager 来做 session 管理,它是依赖于浏览器的 cookie 来维护
+ * session 的,调用 storeSessionId 方法保存sesionId 到 cookie中 为了支持无状态会话,我们就需要继承
+ * DefaultWebSessionManager 自定义生成sessionId 则要实现 SessionIdGenerator
+ * 备注说明:
+ */
+public class ShiroSession extends DefaultWebSessionManager {
+
+ /**
+ * 定义的请求头中使用的标记key,用来传递 token
+ */
+ private static final String AUTH_TOKEN = "authToken";
+
+ private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
+
+ public ShiroSession() {
+ super();
+ // 设置 shiro session 失效时间,默认为30分钟,这里现在设置为15分钟
+ // setGlobalSessionTimeout(MILLIS_PER_MINUTE * 15);
+ }
+
+ /**
+ * 获取sessionId,原本是根据sessionKey来获取一个sessionId
+ * 重写的部分多了一个把获取到的token设置到request的部分。这是因为app调用登陆接口的时候,是没有token的,登陆成功后,产生了token,我们把它放到request中,返回结
+ * 果给客户端的时候,把它从request中取出来,并且传递给客户端,客户端每次带着这个token过来,就相当于是浏览器的cookie的作用,也就能维护会话了
+ *
+ * @param request
+ * @param response
+ * @return
+ */
+ @Override
+ protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
+ // 获取请求头中的 AUTH_TOKEN 的值,如果请求头中有 AUTH_TOKEN 则其值为sessionId。shiro就是通过sessionId
+ // 来控制的
+ String sessionId = WebUtils.toHttp(request).getHeader(AUTH_TOKEN);
+ if (StringUtils.isEmpty(sessionId)) {
+ // 如果没有携带id参数则按照父类的方式在cookie进行获取sessionId
+ return super.getSessionId(request, response);
+
+ } else {
+ // 请求头中如果有 authToken, 则其值为sessionId
+ request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
+ // sessionId
+ request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
+ request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
+ return sessionId;
+ }
+ }
+
+}
diff --git a/src/main/java/com/fc/test/shiro/service/UuidSessionIdGenerator.java b/src/main/java/com/fc/test/shiro/service/UuidSessionIdGenerator.java
new file mode 100644
index 0000000..17b884b
--- /dev/null
+++ b/src/main/java/com/fc/test/shiro/service/UuidSessionIdGenerator.java
@@ -0,0 +1,18 @@
+package com.fc.test.shiro.service;
+
+import java.io.Serializable;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
+import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
+
+public class UuidSessionIdGenerator implements SessionIdGenerator {
+
+ @Override
+ public Serializable generateId(Session session) {
+ // TODO Auto-generated method stub
+ Serializable uuid = new JavaUuidSessionIdGenerator().generateId(session);
+ return uuid;
+ }
+
+}
--
Gitee