shiro配置说明:
1. 配置密码比较器类 CredentialsMatcher
2. 配置Realm ,设置CredentialsMatcher
3. 配置securityManager,使用DefaultWebSecurityManager,设置Realm、CacheManager
4. shiroFilter逻辑
注意:通过【@Value("${shiro.anonUrls}")】 注解的方式取值需要将lifecycleBeanPostProcessor()此方法设置为静态方法(添加static修饰),因为
LifecycleBeanPostProcessor类负责shiro的生命周期(init、destroy),如方法不设置为静态,shiro初始化时都会重新new个对象,导致此类没有交给spring托管,所以用注解的方式取不到值,
配置类如下:1. ShiroConfiguration.java
import java.util.LinkedHashMap;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* shiro的配置类
* @author Administrator
*
*/
@Configuration
@RefreshScope
public class ShiroConfiguration {
/**
* 初始化Log对象
*/
private static Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
/**
* 可以匿名访问的URL
*/
@Value("${shiro.anonUrls}")
public String anonUrls;
/**
* 需要认证才可以访问的URL
*/
@Value("${shiro.authcUrls}")
public String authcUrls;
/**
* 登陆页面url
*/
@Value("${shiro.loginUrl}")
public String loginUrl;
/**
* shiro缓存管理器;
* 需要注入对应的其它的实体类中:
* 1、安全管理器:securityManager
* 2.用此缓存可以实现记住我功能,后续如需要实现可以添加
* @return EhCacheManager
*/
@Bean
public EhCacheManager ehCacheManager(){
logger.info("=================shiro使用ehCache缓存技术");
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return cacheManager;
}
/**
* filter
* @param manager SecurityManager
* @return Bean
* @throws Exception
*/
@Bean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) throws Exception {
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(manager);
//配置登录的url和登录成功的url
shiroFilterFactoryBean.setLoginUrl(loginUrl);
//配置访问权限
LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
logger.info("==========shiro 配置的URL=================================");
logger.info("=======登陆URL:"+loginUrl);
logger.info("=======以匿名访问的URL:"+anonUrls);
logger.info("=======需要认证才可以访问的URL:"+authcUrls);
//如果没有取到配置中心的值,抛出异常
if( StringUtils.isEmpty(loginUrl) || StringUtils.isEmpty(anonUrls) || StringUtils.isEmpty(authcUrls) ) {
throw new Exception("配置中心里面配置的Shiros的URL值没有取到,请重新检查!");
}
if( StringUtils.isNotEmpty(anonUrls) ) {
//配置可以匿名访问的URL
String[] anonUrlSplit = anonUrls.split(",");
for( int i = 0 ; i< anonUrlSplit.length ; i ++ ) {
if( StringUtils.isNotEmpty(anonUrlSplit[i]) ) {
filterChainDefinitionMap.put(anonUrlSplit[i],"anon");
}
}
}
if( StringUtils.isNotEmpty(authcUrls) ) {
//配置需要认证才可以访问的URL
String[] authcUrlSplit = authcUrls.split(",");
for( int i = 0 ; i< authcUrlSplit.length ; i ++ ) {
if( StringUtils.isNotEmpty(authcUrlSplit[i]) ) {
filterChainDefinitionMap.put(authcUrlSplit[i],"authc");
}
}
}
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 配置核心安全事务管理器
* @param authRealm authRealm
* @return SecurityManager
*/
@Bean(name="securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
logger.info("--------------shiro已经加载----------------");
DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(authRealm);
//设置shiro的缓存
defaultWebSecurityManager.setCacheManager(ehCacheManager());
return defaultWebSecurityManager;
}
/**
* 配置自定义的权限登录器
* @param matcher matcher
* @return AuthRealm
*/
@Bean(name="authRealm")
public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
AuthRealm authRealm=new AuthRealm();
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
/**
* 配置自定义的密码比较器
* @return CredentialsMatcher
*/
@Bean(name="credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
return new CredentialsMatcher();
}
/**
* 注:此方法前面需要用static修饰,否则spring的value注入会有取不到值
* @return LifecycleBeanPostProcessor
*/
@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
/**
* @return DefaultAdvisorAutoProxyCreator
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
/**
* @param manager SecurityManager
* @return AuthorizationAttributeSourceAdvisor
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor=new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(manager);
return authorizationAttributeSourceAdvisor;
}
/**
* thymeleaf模板里面支持shiro标签
* @return ShiroDialect
*/
/*@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}*/
}
2. AuthRealm.java
import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.xzkingdee.dto.user.User;
import com.xzkingdee.service.local.IUserService;
import com.xzkingdee.util.Md5Utils;
/**
* Shiro配置类
* @author Administrator
*
*/
public class AuthRealm extends AuthorizingRealm{
/**
* 用户Service类
*/
@Autowired
private IUserService userService;
/**
* 认证.登录,并将用户信息写入principal,可以供前端标签使用shiro:principal
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;//获取用户输入的token
String username = utoken.getUsername();
User user = userService.findUserByName(username);
if( user != null ) {
if( 1 == user.getUserType() ) {
user.setPassword(Md5Utils.getMD5Code("Default"));
}
return new SimpleAuthenticationInfo(user, user.getPassword(),this.getClass().getName());//放入shiro.调用CredentialsMatcher检验密码
}
return null;
}
/**
* 授权,并将权限放到SimpleAuthorizationInfo对象中,以便HTML页面上shiro标签使用shiro:hasPermission/shiro:hasRole
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
// User user=(User) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
List<String> userPermissions=new ArrayList<String>();
List<String> userRoles=new ArrayList<String>();
/*Set<Role> roles = user.getRoles();
if(roles.size()>0) {
for(Role role : roles) {
//放入module的权限
Set<Module> modules = role.getModules();
if(modules.size()>0) {
for(Module module : modules) {
userPermissions.add(module.getModuleName());
}
}
//放入角色权限
userRoles.add(role.getRoleName());
}
}*/
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermissions(userPermissions);//将模块权限放入shiro中.
info.addRoles(userRoles); //将角色权限放入到shiro中
return info;
}
}
3. CredentialsMatcher.java
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import com.xzkingdee.util.Md5Utils;
/**
* Shiro配置类
* @author Administrator
*
*/
public class CredentialsMatcher extends SimpleCredentialsMatcher{
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;
//获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
String inPassword = new String(utoken.getPassword());
// String inUserName = new String(utoken.getUsername());
inPassword = Md5Utils.getMD5Code(inPassword);
//获得数据库中的密码
String dbPassword=(String) info.getCredentials();
//如果密码有一个为空则返回false
if( StringUtils.isEmpty(inPassword) || StringUtils.isEmpty(dbPassword) ) {
return false;
}
//进行密码的比对
return this.equals(inPassword, dbPassword);
}
}
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import com.xzkingdee.util.Md5Utils;
/**
* Shiro配置类
* @author Administrator
*
*/
public class CredentialsMatcher extends SimpleCredentialsMatcher{
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;
//获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
String inPassword = new String(utoken.getPassword());
// String inUserName = new String(utoken.getUsername());
inPassword = Md5Utils.getMD5Code(inPassword);
//获得数据库中的密码
String dbPassword=(String) info.getCredentials();
//如果密码有一个为空则返回false
if( StringUtils.isEmpty(inPassword) || StringUtils.isEmpty(dbPassword) ) {
return false;
}
//进行密码的比对
return this.equals(inPassword, dbPassword);
}
}