版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/pengbin790000/article/details/83620410
之前整合过ssm+shiro+ehcache,也弄过ssh,这次把springboot+redis整合进去
对应的pom:
<!--shiro-->
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<!-- shiro+redis缓存插件 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
</dependency>
1.创建好对应的权限角色表
2.创建shiroConfig,JedisConfig
由于shiro的数据存放于redis,因此,通过
@Value("${redis.spring.redis.host}")
来获取yml配置的redis参数:
redis:
spring:
redis:
database: 1
host: 192.168.3.124
port: 6379
timeout: 5000
通过autowired自动注入,再使用org.crazycake.shiro辅助工具jar来整合redis。
但是:
在启动项目时,springboot加载shiro的顺序似乎是在加载yml配置文件之前,因此,还得修改LifecycleBeanPostProcessorBean 为static方法!!!!
package com.pb.news.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
public class JedisConfig{
@Value("${redis.spring.redis.host}")
private String host;
@Value("${redis.spring.redis.port}")
private Integer port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
}
import com.pb.news.servlet.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
/**
* shiro配置类
*/
@Configuration
public class ShiroConfig {
/**
* LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
* 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
* 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
*/
@Autowired
private JedisConfig jedisConfig;
@Bean(name = "lifecycleBeanPostProcessor")
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* HashedCredentialsMatcher,这个类是为了对密码进行编码的,
* 防止密码在数据库里明码保存,当然在登陆认证的时候,
* 这个类也负责对form里输入的密码进行编码。
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(2);
credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
}
/**
* ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,
* 负责用户的认证和权限的处理,可以参考JdbcRealm的实现。
*/
@Bean(name = "shiroRealm")
@DependsOn("lifecycleBeanPostProcessor")
public ShiroRealm shiroRealm() {
ShiroRealm realm = new ShiroRealm();
// realm.setCredentialsMatcher(hashedCredentialsMatcher());
return realm;
}
// /**
// * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
// * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
// */
// @Bean(name = "ehCacheManager")
// @DependsOn("lifecycleBeanPostProcessor")
// public EhCacheManager ehCacheManager() {
// return new EhCacheManager();
// }
/**
* SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。
* //
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(shiroRealm());
// 自定义缓存实现 使用redis
securityManager.setCacheManager(cacheManager());
// 自定义session管理 使用redis
securityManager.setSessionManager(sessionManager());
// securityManager.setCacheManager(ehCacheManager());
return securityManager;
}
/**
* ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。
* 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
LogoutFilter logoutFilter = new LogoutFilter();
logoutFilter.setRedirectUrl("/login");
// filters.put("logout",null);
shiroFilterFactoryBean.setFilters(filters);
Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
filterChainDefinitionManager.put("/logout", "logout");
filterChainDefinitionManager.put("/user/**", "authc,roles[ROLE_USER]");
filterChainDefinitionManager.put("/events/**", "authc,roles[ROLE_ADMIN]");
// filterChainDefinitionManager.put("/user/edit/**", "authc,perms[user:edit]");// 这里为了测试,固定写死的值,也可以从数据库或其他配置中读取
filterChainDefinitionManager.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
return shiroFilterFactoryBean;
}
/**
* DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
*/
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
/**
* AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,
* 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
aASA.setSecurityManager(securityManager());
return aASA;
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
System.out.println(jedisConfig);
redisManager.setHost("192.168.3.124:6379");
redisManager.setPort(6379);
//redisManager.setExpire(1800);// 配置缓存过期时间
redisManager.setTimeout(0);
// redisManager.setPassword(password);
return redisManager;
}
/**
* Session Manager
* 使用的是shiro-redis开源插件
*/
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
return sessionManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
}
3.创建ShiroRealm
import com.pb.news.dao.vo.UserMapperExt;
import com.pb.news.entity.User;
import com.pb.news.services.RoleService;
import com.pb.news.services.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by cdyoue on 2016/10/21.
*/
public class ShiroRealm extends AuthorizingRealm {
//private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private UserMapperExt userMapperExt;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//logger.info("doGetAuthorizationInfo+"+principalCollection.toString());
//username:principalCollection.getPrimaryPrincipal()
User user = userService.getUserByUserName((String) principalCollection.getPrimaryPrincipal());
User test2 = userMapperExt.test2();
//List<Map<String,Object>> test = userMapperExt.test();
//获取role
List<Map<String,Object>> roleList = new ArrayList<>();
//roleList = roleService.getRolesByUser(user.getId());
//获取permission
List<Map<String,Object>> permissionList = new ArrayList<>();
permissionList = roleService.getRolesPermissionByUser(user.getId());
//把principals放session中 key=userId value=principals
SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()),SecurityUtils.getSubject().getPrincipals());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//赋予角色
//Set<String> roleNameSet = new HashSet<>();
/*if(roleList.size() > 0){
for (Iterator<Map<String, Object>> iterator = roleList.iterator(); iterator.hasNext(); ) {
Map<String, Object> next = iterator.next();
String roleName = (String) next.get("rname");
if(StringUtils.isNoneBlank(roleName)){
info.addRole(roleName);
}
}
}*/
//赋予权限和角色
if(permissionList.size() > 0){
for (Iterator<Map<String, Object>> iterator = permissionList.iterator(); iterator.hasNext(); ) {
Map<String, Object> next = iterator.next();
String roleName = (String) next.get("rname");
String pname = (String) next.get("pname");
if(StringUtils.isNoneBlank(roleName)){
info.addRole(roleName);
}
if(StringUtils.isNoneBlank(pname)){
info.addStringPermission(pname);
}
}
}
/* for(Permission permission:permissionService.getByUserId(user.getId())){
// if(StringUtils.isNotBlank(permission.getPermCode()))
info.addStringPermission(permission.getName());
}*/
//设置登录次数、时间
// userService.updateUserLogin(user);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//logger.info("doGetAuthenticationInfo +" + authenticationToken.toString());
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String userName=token.getUsername();
// logger.info(userName+token.getPassword());
User user = userService.getUserByUserName(token.getUsername());
if (user != null) {
// byte[] salt = Encodes.decodeHex(user.getSalt());
// ShiroUser shiroUser=new ShiroUser(user.getId(), user.getLoginName(), user.getName());
//设置用户session
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute("user", user);
return new SimpleAuthenticationInfo(userName,user.getPassword(),getName());
} else {
return null;
}
// return null;
}
}
4.对应的查询角色以及权限的sql
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.pb.news.dao.vo.UserMapperExt" >
<resultMap id="BaseResultMap" type="com.pb.news.entity.User" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<result column="address" property="address" jdbcType="VARCHAR" />
<result column="tel" property="tel" jdbcType="VARCHAR" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="register" property="register" jdbcType="TIMESTAMP" />
<result column="money" property="money" jdbcType="INTEGER" />
<result column="type" property="type" jdbcType="INTEGER" />
</resultMap>
<select id="selectRoleByUserId" resultType="java.util.HashMap" parameterType="java.lang.Integer">
SELECT
tu.username,
tur.role_id,
tr.id,
tr.role_name as rname
FROM
USER tu
LEFT JOIN user_role tur
ON tu.id = tur.user_id
LEFT JOIN role tr
ON tur.role_id = tr.id
WHERE 1=1 and tu.id = #{id,jdbcType=INTEGER}
</select>
<select id="selectRolePermissionByUserId" resultType="java.util.HashMap" parameterType="java.lang.Integer">
SELECT
tu.username,
tur.role_id,
tr.role_name as rname,
tp.name as pname
FROM
USER tu
LEFT JOIN user_role tur
ON tu.id = tur.user_id
LEFT JOIN role tr
ON tur.role_id = tr.id
LEFT JOIN role_permission trp
ON trp.role_id = tur.role_id
LEFT JOIN permission tp
ON trp.permission_id = tp.id
WHERE 1=1 and tu.id = #{id,jdbcType=INTEGER}
</select>
<select id="test" resultType="java.util.HashMap" >
SELECT
tu.username,
tur.role_id,
tr.id,
tr.name as rname
FROM
USER tu
LEFT JOIN user_role tur
ON tu.id = tur.user_id
LEFT JOIN role tr
ON tur.role_id = tr.id
</select>
<select id="test2" resultMap="BaseResultMap" >
select
*
from user
where id = 1
</select>
</mapper>
参考资料:
https://blog.csdn.net/u012373815/article/details/57532292
https://blog.csdn.net/wuxuyang_7788/article/details/70141812