第一:shiroConfig
package com.ruiguang.config;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.DispatcherType;
/**
*
* @author liuruiguang
*
*/
@Configuration
public class ShiroConfig {
/**
* 首先该文件的第一个配置为FilterRegistrationBean 。 springboot注入过滤器有多种方式,一种是最简单的@WebFilter注解,一种就是下边的这种,写一个FilterRegistrationBean,然后将自定义过滤器set进去,下边是通过DelegatingFilterProxy 代理的方式,注入容器中名字为shiroFilter 的过滤器,最后设置过滤器的规则。
*/
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
/**
*DelegatingFilterProxy做的事情是代理Filter的方法,从application
*context里获得bean,从下边可以理解到,它是将容器中名字为shiroFilter
*的过滤器加入到过滤器注册bean中
**/
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
filterRegistration.setEnabled(true);
filterRegistration.addUrlPatterns("/*"); //过滤规则,即所有的请求
filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
return filterRegistration;
}
/**
* 过滤器 过滤shiroFilter
* @param securityManager
* @return
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//拦截器.
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* )
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
System.out.println("hashedCredentialsMatcher---->>>"+hashedCredentialsMatcher);
return hashedCredentialsMatcher;
}
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
//myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());//加密
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());//加密
System.out.println("myShiroRealm--->>>"+myShiroRealm.getName().toString());
System.out.println("myShiroRealm--->>>"+myShiroRealm.getCredentialsMatcher().toString());
return myShiroRealm;
}
/**
* @see DefaultWebSessionManager
* @return
*/
@Bean(name="sessionManager")
public DefaultWebSessionManager defaultWebSessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//sessionManager.setCacheManager(cacheManager());
sessionManager.setGlobalSessionTimeout(1800000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setDeleteInvalidSessions(true);
//
sessionManager.setSessionIdCookie(getSessionIdCookie());
return sessionManager;
}
/**
* 给shiro的sessionId默认的JSSESSIONID名字改掉
* @return
*/
@Bean(name="sessionIdCookie")
public SimpleCookie getSessionIdCookie(){
SimpleCookie simpleCookie = new SimpleCookie("webcookie");
/**
* HttpOnly标志的引入是为了防止设置了该标志的cookie被JavaScript读取,
* 但事实证明设置了这种cookie在某些浏览器中却能被JavaScript覆盖,
* 可被攻击者利用来发动session fixation攻击
*/
simpleCookie.setHttpOnly(true);
/**
* 设置浏览器cookie过期时间,如果不设置默认为-1,表示关闭浏览器即过期
* cookie的单位为秒 比如60*60为1小时
*/
simpleCookie.setMaxAge(-1);
return simpleCookie;
}
/**
*3. 通过上边的shiroFilter 的配置之后,然后再看securityManager。
* @return
*/
@Bean(name="securityManager")
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());//在这里的UserRealm 类继承于AuthorizingRealm ,该类的作用其实有用户密码验证、权限授权等。这个也会在后边贴出来,先继续讲shiroConfig 文件。
//要是对session的配置,比如,超时时间的设置等,基本上都是跟session相关的配置。另外,上边还有getSessionIdCookie() 方法的引用,众所周知,浏览器与后台系统交互的方式,是以后台存储session,然后将该session对应key,以字符串的形式返给浏览器,并在浏览器中以cookie 的形式记录起来,方便后续的访问,如果浏览器丢失了这个cookie,那就会失去与后台系统的联系,必须重新登录,才能重新再生成这个cookie。而getSessionIdCookie() 方法,即是对cookie在浏览器那里的名字的定义,如下:
securityManager.setSessionManager(defaultWebSessionManager());
return securityManager;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException","403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
//r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
}