一、shiro介绍
借用官方的话:Apache Shiro是一个功能强大、易于使用的Java安全框架,它常用于身份验证、授权、加密和会话管理。Shiro的API易于理解,您可以快速轻松地保护任何应用程序——从小的移动应用程序到大的Web和企业应用程序。
二、spring boot整合shiro
1.maven资源
我使用的版本是1.4.0
<!--shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
2.shiroConfig 配置类:注释很详细,缓冲如果不需要可以不要,shiro默认有一套缓存规则。
package com.cn.iris.common.config;
import com.cn.iris.common.core.shiro.LoginRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
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.beans.factory.annotation.Qualifier;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Author: IrisNew
* Description: shiro 配置
* Date: 2018/6/6 16:45
*/
@Configuration
public class ShiroConfig {
/**
* 缓存管理器 使用Ehcache实现
*/
@Bean
public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(ehcache.getObject());
return ehCacheManager;
}
/**
* ShiroFilterFactoryBean 处理拦截资源文件问题
* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
*
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager){
ShiroFilterFactoryBean sfbBean = new ShiroFilterFactoryBean();
sfbBean.setSecurityManager(securityManager);
//设置默认登陆页
sfbBean.setLoginUrl("/welcome");
//登陆成功后跳转的url
sfbBean.setSuccessUrl("/index");
//设置权限不足跳转
sfbBean.setUnauthorizedUrl("/403");
//自定义过滤器
/*Map<String, Filter> filters=new HashMap<>();
filters.put("per",getPermissionFilter());
filters.put("verCode",getVerfityCodeFilter());
sfbBean.setFilters(filters);*/
/** 配置访问权限
* 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
* anon 不需要认证
* authc 需要认证
*/
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/css/**","anon");
filterMap.put("/js/**","anon");
filterMap.put("/welcome","anon");
filterMap.put("/userlogin","anon");
filterMap.put("/getVeCode","anon");
filterMap.put("/logout","logout");
filterMap.put("/plugin/**","anon");
filterMap.put("/**","authc");
sfbBean.setFilterChainDefinitionMap(filterMap);
return sfbBean;
}
// 配置核心安全事务管理器
@Bean(name = "securityManager")
public SecurityManager securityManager(@Qualifier("loginRealm") LoginRealm loginRealm,CacheManager cacheShiroManager) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
//自定义的权限登录器
manager.setRealm(loginRealm);
//自定义的session管理器
// manager.setSessionManager(sessionManager);
//自定义缓存策略
manager.setCacheManager(cacheShiroManager);
return manager;
}
//配置自定义的权限登录器
@Bean(name = "loginRealm")
public LoginRealm getLoginRealm(){
LoginRealm realm= new LoginRealm();
realm.setCredentialsMatcher(credentialsMatcher());
return realm;
}
// 配置自定义的密码匹配比较器
@Bean(name = "credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
return new SimpleCredentialsMatcher();
}
/**
* 启用shrio授权注解拦截方式,AOP式方法级权限检查
*/
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor as=new AuthorizationAttributeSourceAdvisor();
as.setSecurityManager(securityManager);
return as;
}
}
3.自定义Realm,这个是所有用shiro都需要自定义的。
其中userServiceImpl的findByAcc方法是用账号查询用户实体返回;
role2menuService的getMenuCodesByRoleIds方法是用来查询角色对应的所有菜单及增删改查权限的。
package com.cn.iris.common.core.shiro;
import com.cn.iris.admin.entity.User;
import com.cn.iris.admin.service.IRole2menuService;
import com.cn.iris.admin.service.IUserService;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* Author: IrisNew
* Description: shiro权限登录器
* Date: 2018/6/8 16:14
*/
@Service
public class LoginRealm extends AuthorizingRealm {
@Autowired
private IUserService userServiceImpl;
@Autowired
private IRole2menuService role2menuService;
// 认证.登录 提供账户信息返回认证信息
/**
* 当调用如下代码时会进入这个方法(一般是登录页面)
* Subject currentUser = SecurityUtils.getSubject();
* currentUser.login(token);
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // 获取用户输入的token
//输入的用户名
String userAcc = token.getUsername();
User user = userServiceImpl.findByAcc(userAcc);
if (user == null) {
throw new UnknownAccountException("账号或者密码错误!");
}
return new SimpleAuthenticationInfo(user, user.getUserPsw(), getName());
}
// 授权
// 提供用户信息返回权限信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取session中的用户
User user = (User) principalCollection.getPrimaryPrincipal();
List<String> roIdsList = user.getRoleIds();
List<String> permissionsList = role2menuService.getMenuCodesByRoleIds(roIdsList);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roIdsList);
if(permissionsList != null && permissionsList.size()>0){
info.addStringPermissions(permissionsList); // 将权限放入shiro中.
}
return info;
}
}
4.工具类,方便获取当前登陆的session及Subject对象。
package com.cn.iris.common.core.shiro;
import com.cn.iris.admin.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
/**
* Author: IrisNew
* Description:shiro工具类
* Date: 2018/6/11 14:48
*/
public class ShiroUtil {
/**
* 获取当前 Subject
*/
public static Subject getSubject(){
return SecurityUtils.getSubject();
}
/**
* 获取登陆用户
*/
public static User getUser(){
return (User)getSubject().getPrincipals().getPrimaryPrincipal();
}
/**
* 验证用户是否属于某角色
*/
public boolean hasRole(String roleName) {
return getSubject() != null && roleName != null && roleName.length() > 0 && getSubject().hasRole(roleName);
}
/**
* 验证用户是否拥有指定权限
*/
public boolean hasPermission(String permission) {
Subject subject = getSubject();
return getSubject() != null && permission != null
&& permission.length() > 0
&& getSubject().isPermitted(permission);
}
public static Session getSession(){
return getSubject().getSession();
}
}
5.登陆及登出调用(代码段)
@GetMapping("/userlogin")
public String index(HttpServletRequest request, String userAcc, String userPsw) {
Subject subject = ShiroUtil.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userAcc.trim(),userPsw);
subject.login(token);
User user = userServiceImpl.findByAcc(userAcc);
if(user.getUserPsw().equals(userPsw)){
logger.info("用户登陆:"+user.getNickName());
return "redirect:/index";
}
return "login";
}
//跳转至登陆页
@GetMapping("/logOut")
public String logOut() {
ShiroUtil.getSubject().logout();
return "/login";
}
前端页面就不将代码贴出来了。
我本人的自己写了个简单的springboot项目,整合了shiro,是一套完整的项目管理类项目,开源免费。
感兴趣的可以看看:Iris-开源的后台管理类项目;希望能高台贵手,给小弟一个star.感谢!