准备工作
org.apache.shiro
shiro-all
1.2.5
org.apache.shiro
shiro-ehcache
1.3.2
1:创建ShiroConfigBean
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfigBean {
@Bean
public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {
System.out.println("初始化拦截器");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器.
Map filterChainDefinitionMap = new LinkedHashMap();
// 设置login URL
shiroFilterFactoryBean.setLoginUrl("/login");
//游客,开发权限
filterChainDefinitionMap.put("/guest/**", "anon");
//用户,需要角色权限 “user”
filterChainDefinitionMap.put("/user/**", "roles[user]");
//管理员,需要角色权限 “admin”
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//开放登陆接口
filterChainDefinitionMap.put("/login", "anon");
//其余接口一律拦截
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/*
* 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* 所以我们需要修改下doGetAuthenticationInfo中的代码; )
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
System.out.println("密码匹配器");
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1);// 散列的次数,比如散列两次,相当于md5(md5(""));
return hashedCredentialsMatcher;
}
//
@Bean
public MyShiroRealm myShiroRealm() {
System.out.println("进入relam");
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public DefaultWebSecurityManager securityManager() {
System.out.println("将relam注入到securityManager");
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 注入自定义的realm;
securityManager.setRealm(myShiroRealm());
// 注入缓存管理器;
securityManager.setCacheManager(ehCacheManager());
return securityManager;
}
/*
* 开启shiro aop注解支持 使用代理方式;所以需要开启代码支持;
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
DefaultWebSecurityManager securityManager) {
System.out.println("开启注解模式");
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
*/
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
/*
* shiro缓存管理器;
* 需要注入对应的其它的实体类中-->安全管理器:securityManager可见securityManager是整个shiro的核心;
*/
@Bean
public EhCacheManager ehCacheManager() {
System.out.println("shiro缓存");
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return cacheManager;
}
}
2:编写自定义的realm
import com.tuyue.entity.User;
import com.tuyue.mapper.PermissionMapper;
import com.tuyue.mapper.RoleMapper;
import com.tuyue.mapper.UserMapper;
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.UnknownAccountException;
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.apache.shiro.util.ByteSource;
import org.apache.shiro.util.StringUtils;
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;
/**
* realm实现类,用于实现具体的验证和授权方法
* @author Bean
*
*/
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
@Autowired
private PermissionMapper permissionMapper;
/**
* 方面用于加密 参数:AuthenticationToken是从表单穿过来封装好的对象
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("开始验证是否登录" + token.getPrincipal());
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 获得从表单传过来的用户名
String username = upToken.getUsername();
if(username==null||username.length()==0){
return null;
}
User user=new User();
user.setUsername(username);
User user1 = userMapper.selectOne(user);
// 如果用户不存在,抛此异常
if (user1==null) {
throw new UnknownAccountException("无此用户名!");
}
// 认证的实体信息,可以是username,也可以是用户的实体类对象,这里用的用户名
Object principal = user1;
// 颜值加密的颜,可以用用户名
ByteSource credentialsSalt = ByteSource.Util.bytes("222");
// 当前realm对象的名称,调用分类的getName()
String realmName = this.getName();
// 创建SimpleAuthenticationInfo对象,并且把username和password等信息封装到里面用户密码的比对是Shiro帮我们完成的
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, user1.getPassword(),credentialsSalt, realmName);
return info;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
// 用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权方法执行");
Set roles = new HashSet<>();
Set permissions = new HashSet<>();
User user= (User) principals.getPrimaryPrincipal();
List list = roleMapper.selectByUserId(user.getId());
for (String s : list) {
roles.add(s);
}
List list1 = permissionMapper.selectByuserId(user.getId());
for (String s : list1) {
permissions.add(s);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
//添加权限
info.setStringPermissions(permissions);
return info;
}
}
3:创建数据库
USE `shiro`;
/*Table structure for table `permission` */
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`permission_name` varchar(20) DEFAULT NULL,
`source` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
/*Data for the table `permission` */
insert into `permission`(`id`,`permission_name`,`source`) values (1,'添加用户','user:save'),(2,'删除用户','user:del'),(3,'修改用户','user:up'),(4,'添加商品','goods:save'),(5,'修改商品','goods:up'),(6,'删除商品','goods:del');
/*Table structure for table `permission_role` */
DROP TABLE IF EXISTS `permission_role`;
CREATE TABLE `permission_role` (
`permission_id` int(11) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `permission_role` */
insert into `permission_role`(`permission_id`,`role_id`) values (1,1),(2,1),(3,1),(4,2),(5,2),(6,2);
/*Table structure for table `role` */
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*Data for the table `role` */
insert into `role`(`id`,`role_name`) values (1,'用户管理员'),(2,'商品管理员');
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'123','c26a263602b986958afab92363c5984f'),(2,'456','456');
/*Table structure for table `user_role` */
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*Data for the table `user_role` */
insert into `user_role`(`id`,`user_id`,`role_id`) values (1,1,1),(2,2,2);
4:编写controller进行测试
(1)先测试登录
@RequestMapping("/login")
public String loginUser(String username,String password) {
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(usernamePasswordToken); //完成登录
boolean aaa = subject.hasRole("用户管理员");
System.out.println("2222"+aaa);
return "登录成功";
} catch(Exception e) {
e.printStackTrace();
return "登陆失败";
}
}
(2) 测试权限
@RequestMapping("test")
@RequiresAuthentication
@RequiresPermissions("user:del")
public String test() {
Subject subject = SecurityUtils.getSubject();
return "当前对象:"+subject.getPrincipal().toString();
}