之前一直使用spring security来做安全管理,感觉配置稍微有点复杂,于是尝试了下shiro,感觉的确简单不少。记录下配置和实现过程。
因为还是spring的底子,所以用的shiro-spring,首先用maven把相关包弄下来
dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency>
我用的版本是1.2.2
然后开始增加shiro的配置文件,xml里增加了shiro的配置引入,同时增加相应的filter
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:/application-root.xml, classpath*:/application-shiro.xml </param-value> </context-param> <!-- shiro security filter --> <filter> <!-- 这里的filter-name要和spring的applicationContext-shiro.xml里的 org.apache.shiro.spring.web.ShiroFilterFactoryBean的bean name相同 --> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
下面是shiro的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd" default-lazy-init="true"> <description>Shiro安全配置</description> <bean id="chainDefinitionSectionMetaSource" class="xxx.xxx.ChainDefinitionSectionMetaSource"> <property name="filterChainDefinitions"> <value> /login = authc /logout = logout /admin/** = roles[admin] /static/** = anon /eventSurvey/** = anon /notice/** = anon /** = authc </value> </property> </bean> <!-- Shiro's main business-tier object for web-enabled applications --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroDbRealm" /> </bean> <!-- 項目自定义的Realm, 所有accountService依赖的dao都需要用depends-on声明 --> <bean id="shiroDbRealm" class="xxx.xxx.ShiroDbRealm"> <property name="credentialsMatcher" ref="flameCredentialsMatcher" /> </bean> <bean id="flameCredentialsMatcher" class="xxx.xxx.FlameCredentialsMatcher"> </bean> <!-- Shiro Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login" /> <property name="successUrl" value="/" /> <property name="unauthorizedUrl" value="/authError" /> <property name="filters"> <map> <entry key="authc"> <bean class="xxx.xxx.MyFormAuthenticationFilter"></bean> </entry> <entry key="roles"> <bean class="org.apache.shiro.web.filter.authz.RolesAuthorizationFilter"></bean> </entry> </map> </property> <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" /> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
这里需要说明几个配置
1)shiro本身的过滤配置已经很好了,但我们要求可从数据库加载过滤配置,所以增加了chainDefinitionSectionMetaSource的实现,用来同时从配置文件和数据库加载过滤信息,实现如下
public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section>{ @Autowired private ResourceDao resourceDao; private String filterChainDefinitions; public Section getObject() throws BeansException { //获取所有Resource List<Resource> list = resourceDao.findAll(); Ini ini = new Ini(); //加载默认的url ini.load(filterChainDefinitions); Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); //循环Resource的url,逐个添加到section中。section就是filterChainDefinitionMap, //里面的键就是链接URL,值就是存在什么条件才能访问该链接 for (Resource resource : list) { //如果不为空值添加到section中 if(StringUtils.hasText(resource.getUrl()) && StringUtils.hasText(resource.getPerms())) { section.put(resource.getUrl(), resource.getPerms()); } } return section; } /** * 通过filterChainDefinitions对默认的url过滤定义 * * @param filterChainDefinitions 默认的url过滤定义 */ public void setFilterChainDefinitions(String filterChainDefinitions) { this.filterChainDefinitions = filterChainDefinitions; } public Class<?> getObjectType() { return this.getClass(); } public boolean isSingleton() { return false; } }
这里的Resource是从数据库得到的数据,其他跟xml配置差不多,就是key-value一样的。
2)shiroDbRealm,负责根据自己的业务抓取用户信息,主要是为了安全认证用
public class ShiroDbRealm extends AuthorizingRealm{ @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { UserInfo user = (UserInfo) principals.getPrimaryPrincipal(); List<String> userAuths = user.getAuthList(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRoles(userAuths); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; UserInfo user = userService.findUserById(token.getUsername()); if (user != null) { String authPassword = user.getPassword(); return new SimpleAuthenticationInfo(user, authPassword,getName()); } else { return null; } } }
3)credentialsMatcher,这里是处理密码匹配用的,通常密码都是加密的,用户前台输入的密码需要自己加密算法来匹配
/** * 处理密码加密 * @author lee * */ public class FlameCredentialsMatcher extends SimpleCredentialsMatcher{ @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { String userId = token.getPrincipal().toString(); char[] ps = (char[]) token.getCredentials(); StringBuffer sb = new StringBuffer(); for(char p : ps){ sb.append(p); } String tokenMd5Pw = Encryption.encrypt(userId,sb.toString()); return equals(tokenMd5Pw, info.getCredentials()); } }
上面的Encryption.encrypt(userId,sb.toString())是一个加密算法处理,这个可以使用shiro的加密API,也可以自己实现。info是shiroDbRealm取回的用户信息,token是前台传过来的信息。
4)对于shiro的过滤链我使用了两个简单的,一个是处理登录和权限校验的authc,一个是处理角色校验的roles,这里需要说下的是如果在filter中不增加roles,那么配置/admin/** = roles[admin]这种就不会生效。对于authc因为要做是否是ajax的验证,所以做了自己的实现封装
public class MyFormAuthenticationFilter extends FormAuthenticationFilter{ private static final Logger log = LoggerFactory.getLogger(MyFormAuthenticationFilter.class); /* * 主要是针对登入成功的处理方法。对于请求头是AJAX的之间返回JSON字符串。 */ @Override protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { if (!isAjax(request)) {// 不是ajax请求 issueSuccessRedirect(request, response); } else { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("{\"success\":true,\"message\":\"登入成功\"}"); out.flush(); out.close(); } return false; } /** * 主要是处理登入失败的方法 */ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { if (!isAjax(request)) {// 不是ajax请求 setFailureAttribute(request, e); return true; } try { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain;charset=utf-8"); PrintWriter out = response.getWriter(); String message = e.getClass().getSimpleName(); if ("IncorrectCredentialsException".equals(message)) { out.println("{\"success\":false,\"message\":\"密码错误\"}"); } else if ("UnknownAccountException".equals(message)) { out.println("{\"success\":false,\"message\":\"账号不存在\"}"); } else if ("LockedAccountException".equals(message)) { out.println("{\"success\":false,\"message\":\"账号被锁定\"}"); } else { out.println("{\"success\":false,message:\"未知错误\"}"); } out.flush(); out.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } return false; } /** * 所有请求都会经过的方法。 */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { log.info("权限验证"); if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (log.isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); } return executeLogin(request, response); } else { if (log.isTraceEnabled()) { log.trace("Login page view."); } //allow them to see the login page ;) return true; } } else { if (log.isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]"); } if (!isAjax(request)) {// 不是ajax请求 saveRequestAndRedirectToLogin(request, response); } else { response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("{\"success\":false,\"message\":\"login\"}"); out.flush(); out.close(); } return false; } } private boolean isAjax(ServletRequest request){ HttpServletRequest httpServletRequest = (HttpServletRequest) request; return "XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With")); } }
都配置完成,shiro就跑起来了
相关推荐
spring springmvc mybatis shiro 以及 ehcache(配合shiro实现缓存验证 配合spring实现二级缓存) 测试 二级缓存 访问http://localhost:8080/vkblog/test/ehcacheuserlist.action 测试 访问限制 访问任意的action
shiro配合sping框架
循序渐进,学习Spring Boot、Spring Boot & Shiro、Spring Cloud、Spring Security & Spring Security OAuth2,博客Spring系列源码 一、Spring Boot教程 开启Spring Boot Spring Boot基础配置 Spring Boot中使用...
因为我们是与spring进行集成的,而spring的基本就是web项目的xml文件。所以我们在web.xml中配置shiros的过滤拦截。正常情况下,我们需要将shiro的filter配置在所有的filter前面,当然和encodingFilter这个filter是不...
https://blog.csdn.net/qq_43439968/article/details/108702178 简单的Shiro-SpringBoot整合项目,配合博客查看,和狂神的spring视频查看
SpringMyBatisShiro 项目启动后输入: 该项目中, 增加了对url的拦截, 用admin/123456,拥有index权限reports未任何权限, lance/123456尚未分配任何权限. 参考 shiro Cache交于Redis进行管理 SpringBoot整合A.CTable ...
快速搭建项目原型,基于Spring + Spring MVC + Mybatis,简单轻便、易于扩展的架构,适用于大多数项目 封装了常用的CURD,配合mybatis-generator 自动生成dao、model、mapper层,减少重复劳动,提高生产力,实现快速...
轻松满足企业级项目需求更多功能介绍,请参考 | | |技术体系1、Nacos 服务注册和发现2、Nacos 统一配置中心3、熔断降级限流 sentinel4、feign配合sentinel使用5、SpringCloud Gateway6、JWT + Shiro 权限控制7、...
本项目架构采用Mybatis+Spring+SpringMVC作为基础框架 使用apache-shiro作为安全登录及权限验证框架 使用fastjson作数据处理 使用slf4j+log4j做日志记录 使用druid做连接池及监控 采用mysql作为数据库 使用kaptcha并...
抛弃Shiro、Spring Security等安全框架繁琐的配置,改为注解实现权限管理,配合Spring MVC的RequestMapping注解,完美实现细粒度的权限控制。
1.概要介绍ueboot是一个基于spring boot2 + vue2.0+iview3.0的基础开发平台,通过这个平台可以快速完成某些CRUD功能的系统(从前端到Swift快速实现)基于iViewUI提供了一套CRUD快速开发UI组件,只需要配置json就可以...
本课程讲解Shiro三种使用方案,分为为原生用法,整合Spring用法,和整合SpringBoot的用法?本课程讲解Shrio结合数据库的RBAC表进行动态的用户认证和授权的实现过程该课程属于《Java全栈工程师》学习路线中的一门,...
后端采用Spring Boot、Shiro、Redis。 权限认证使用Shiro。 支持加载动态权限菜单,多方式轻松权限控制。 特色功能 1、可视化工作流,仿钉钉工作流。 2、自定义表单问卷调查,数据收集系统。 3、Vue网页版在线...
若系统配置允许,可使用Solr代替),IKAnaylzer(智能的中文分词器,配合Maven使用需手动将其jar包加入到仓库) shiro(相对于Spring Security,结构简单,功能完整的安全框架) Ehcache(纯Java的进程内缓存框架,是一种...
2. Apache Shiro 1.3.2 3. Lombok 4. WebSocket 5. Mysql、Mybatis、Mapper、Pagehelper 6. Spring Data Jpa 7. fastJson 8. swagger-ui 9. qiniu 使用说明 1. 在mysql中导入项目的sql文件 2. 将项目中yml配置文件中...
cloud,详细的技术描述参考jeecg-cloud MES更新了底层框架未ruoyi,技术体系表现在1、Nacos 服务注册和发现 2、Nacos 统一配置中心 3、熔断降级限流 sentinel 4、feign配合sentinel使用 5、SpringCloud Gateway 6、...
2. Apache Shiro 1.3.2 3. Lombok 4. WebSocket 5. Mysql、Mybatis、Mapper、Pagehelper 6. Spring Data Jpa 7. fastJson 8. swagger-ui 9. qiniu 使用说明 1. git clone 本项目 2. 在mysql中导入项目的sql文件 3. ...
wx-manage提供公众号菜单、自动回复、公众号素材、简易CMS、等管理功能,请注意本项目仅为管理后台界面,需配合后端程序wx-api一起使用 技术选型: 核心框架:Spring Boot 安全框架:Apache Shiro 持久层框架:...
项目使用jdk1.8,MySQL8.1.12版本,Tomcat8,spring,springboot,mybatis,redis5.0版本,log4j构建而成,如果后期项目需要则需要加入shiro框架集成 包括控制层和视图均已配置完成,dao层操作已配合redis实现,包含...
2.wx-manage提供公众号菜单、自动回复、公众号素材、简易CMS、等管理功能,请注意本项目仅为管理后台界面,需配合后端程序wx-api一起使用 技术选型: 核心框架:Spring Boot 安全框架:Apache Shiro 持久层框架:...