ShiroConfig 配置类:
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.ck.syscheck.shiro.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
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.SimpleCookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 创建ShiroFilterFactoryBean
*
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* 常用过滤器
* anon:无需认证(登录)就可以访问
* authc:必须认证才可以访问
* user:如果使用RememberMe的功能,可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
//登录的url
shiroFilterFactoryBean.setLoginUrl("/api/loginPage");
// 未授权url
shiroFilterFactoryBean.setUnauthorizedUrl("/api/unAuth");
// 登录成功后跳转的url
shiroFilterFactoryBean.setSuccessUrl("/index");
//注意此处要使用LinkenHashMap
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/", "authc");
// 定义filterChain,静态资源不拦截
filterMap.put("/css/**", "anon");
filterMap.put("/js/**", "anon");
filterMap.put("/fonts/**", "anon");
filterMap.put("/img/**", "anon");
//放行某些个请求
filterMap.put("/api/test", "anon");
filterMap.put("/api/login", "anon");
//授权过滤器,如果未授权会跳转到相应的页面
filterMap.put("/api/add", "perms[api:add]");
// 除上以外所有url都必须认证通过才可以访问,未通过认证自动访问LoginUrl
// filterMap.put("/api/*", "authc");
// filterMap.put("/home/*","authc");
// filterMap.put("/config/*","authc");
// 配置退出过滤器,其中具体的退出代码 Shiro已经替我们实现了
filterMap.put("/logout", "logout");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/***
* 创建DefaultWebSecurityManager
* @param matcher
* @return
*/
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(shiroRealm(matcher));
//记住我
securityManager.setRememberMeManager(rememberMeManager());
//缓存管理
securityManager.setCacheManager(getEhCacheManager());
return securityManager;
}
/**
* 创建Relm
*
* @return
*/
@Bean
public ShiroRealm shiroRealm(HashedCredentialsMatcher matcher) {
ShiroRealm myShiroRealm = new ShiroRealm();
myShiroRealm.setCredentialsMatcher(matcher);
return myShiroRealm;
}
/**
* 配置ShiroDialect,用于整合shiro和Thymeleaf标签配合使用
* @return
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
/**
* 密码匹配凭证管理器
*
* @return
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 采用MD5方式加密
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
// 设置加密次数
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
/**
* cookie对象
* @return
*/
public SimpleCookie rememberMeCookie() {
// 设置cookie名称,对应login.html页面的<input type="checkbox" name="rememberMe"/>
SimpleCookie cookie = new SimpleCookie("rememberMe");
// 设置cookie的过期时间,单位为秒,这里为一天
cookie.setMaxAge(86400);
return cookie;
}
/**
* cookie管理对象
* @return
*/
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
// rememberMe cookie加密的密钥
cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
return cookieRememberMeManager;
}
/**
* 注入Ehcache缓存
* @return
*/
@Bean
public EhCacheManager getEhCacheManager() {
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
return ehCacheManager;
}
}
此类主要使用 hashedCredentialsMatcher
其加盐处理:
/**
* 密码匹配凭证管理器
*
* @return
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 采用MD5方式加密
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
// 设置加密次数
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
ShiroRealm 类:
import com.ck.syscheck.model.*;
import com.ck.syscheck.service.SysResourceService;
import com.ck.syscheck.service.SysRoleResourceService;
import com.ck.syscheck.service.SysUserRoleService;
import com.ck.syscheck.service.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
public class ShiroRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private SysUserService sysUserService;
@Resource
private SysUserRoleService sysUserRoleService;
/**
* 处理授权逻辑
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("执行授权逻辑+" + principalCollection.toString());
//给资源进行授权
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject();
SysUser user = (SysUser) subject.getPrincipal();
//获取用户角色ID
SysUserRole byUserId = sysUserRoleService.findByUserId(user.getUid());
//此处必须要和配置文件里的授权保持一致
authorizationInfo.addStringPermission("api:add");
return authorizationInfo;
}
/**
* 处理认证逻辑
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
// 获取用户输入的用户名和密码
String userName = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
if (StringUtils.isNotBlank(userName)) {
SysUser user = sysUserService.list(userName);
//检测是否有此用户
if (user == null) {
// 没有找到账号异常
throw new UnknownAccountException("用户名或密码错误!");
}
if (!token.getUsername().equals(user.getUsername())) {
return null;
}
if (user.getStatus().equals("0")) {
throw new LockedAccountException("账号已被锁定,请联系管理员!");
}
// 获取盐值,即用户名
ByteSource salt = ByteSource.Util.bytes("AaBbCc");
// 将账户名,密码,盐值,realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), salt, getName());
//返回密码
return simpleAuthenticationInfo;
}
return null;
}
}
在Realm类中主要传递加盐的值:
// 获取盐值,即用户名,此处盐值可以是活的,可以是用户输入的用户名等,也可以是写死的
ByteSource salt = ByteSource.Util.bytes("AaBbCc");
// 将账户名,密码,盐值,realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), salt, getName());
//返回密码
return simpleAuthenticationInfo;
测试Shiro加盐,一般在注册的时候进行如下处理,最后保存到数据库。
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
/**
* 测试Shiro加盐,一般在注册的时候进行如下处理,最后保存到数据库
* @author ck
* @date 2019/7/8
*/
public class Test {
public static void main(String[] args) {
String newPs = new SimpleHash("MD5", "123456", ByteSource.Util.bytes("AaBbCc"), 1024).toHex();
System.out.println(newPs);
//6a630026f54e3af745becaa18dd1ca6f
}
}