什么是shiro安全框架,以及在springboot中如何使用
Posted lovoo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是shiro安全框架,以及在springboot中如何使用相关的知识,希望对你有一定的参考价值。
一、 概述
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
- 其中 SecurityManager是核心,相当于Spring MVC的前端控制器,起管家调度作用。
- Subject可以理解为账户。来验证其是否合法或者权限。
- Realms可以理解为数据源,即程序从Realm中拿数据来确认该用户时候是合法,权限等。Realm可以自己实现,继承Realm即可。下面这个例子默认Realm的来源为ini配置文件,即zhang=123
wang =123.符合这两个即ok.
二、作用与总结
- shiro 主要就是对访问系统需要对系统授权 和认证;他专门有一个安全管理器, 这个安全管理器包含授权器和认证器,方法授权和认证都是通过这两个方法;
- sessionmanager session 管理器 一般单点登录就是这样设置的。
- cache管理器,主要是将授权缓存起来, 一般shiro通过数据库交互都是通过realm存储授权与逻辑判断:比如判断当前角色有哪些权限,Realm实质上是一个安全相关的DAO。
- shiro的角色是动态创建的,一般是一个角色对应一组权限,这样就非常灵活。
- 说道安全框架肯定离不开密码。 shiro拥有密码管理器与密码加密加盐等等一些列对用户加密的操作。
三、在SpringBoot项目中集成
- 首先引入依赖,
- 然后继承AuthorizingRealm实现权限认证与授权,
- 再配置缓存与Cookie,
- 登录时进行密码验证
1、引入相关依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.6.0</version>
</dependency>
2、UserRealm相关代码
@Component
@Slf4j
public class UserRealm extends AuthorizingRealm {
// 在shiro框架中(UserRealm)使用过@Autowire注入的类,缓存注解和事务注解都失效。
// 解决方法:
// 1.在Shiro框架中注入Bean时,不使用@Autowire,使用ApplicationContextRegister.getBean()方法,手动注入bean。保证该方法只有在程序完全启动运行时,才被注入。
// 2.使用@Autowire+@Lazy注解,设置注入到Shiro框架的Bean延时加载(即在第一次使用的时候加载)。
@Lazy
@Autowired
private UserService userService;
@Lazy
@Autowired
private MenuService menuService;
/**
* 授权(验证权限时调用)
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User)principals.getPrimaryPrincipal();
String userId = user.getId();
String username = user.getUsername();
Session session = ShiroUtil.getSession();
Set<String> rolesSet = (Set<String>) session.getAttribute("rolesSet");
Set<String> permsSet = (Set<String>) session.getAttribute("permsSet");
session.setAttribute("user", user);
session.setAttribute("username", username);
List<String> permsList = menuService.getPermission(userId);
//用户权限列表
if (CollectionUtils.isEmpty(permsSet)) {
permsSet = new HashSet<String>();
for(String perms : permsList){
if(StrUtil.isBlank(perms)){
continue;
}
permsSet.addAll(Arrays.asList(perms.trim().split(",")));
}
session.setAttribute("permsSet", permsSet);
}
if (CollectionUtils.isEmpty(rolesSet)) {
rolesSet = userService.listUserRoles(userId);
session.setAttribute("rolesSet", rolesSet);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//设置权限
info.setStringPermissions(permsSet);
//设置角色
info.setRoles(rolesSet);
return info;
}
/**
* 认证(登录时调用)
* @param authcToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
MyUsernamePasswordToken token = (MyUsernamePasswordToken)authcToken;
//门店编号
String storeCode = token.getStoreCode();
if(StrUtil.isEmpty(storeCode)){
throw new UnknownAccountException("请输入门店号!");
}
//查询用户信息
// User user = userService.getByUsername(token.getUsername());
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("store_code", storeCode);
wrapper.eq("username", token.getUsername());
wrapper.eq("IFNULL(status, 1)", 1);
User user = userService.getOne(wrapper);
//账号不存在
if(user == null) {
throw new UnknownAccountException("账号或密码不正确!");
}
String password = CryptionKit.genUserPwd(new String((char[]) token.getCredentials()));
if (!user.getPassword().equals(password)) {
// 密码错误
throw new IncorrectCredentialsException("账号或密码不正确!");
}
if (user.getStatus() != SysConstant.VALID_USER) {
// 账号锁定
throw new LockedAccountException("账号已被锁定,请联系管理员!");
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
shaCredentialsMatcher.setHashAlgorithmName(ShiroUtil.HASH_ALGORITHM_NAME);
shaCredentialsMatcher.setHashIterations(ShiroUtil.HASH_ITERATIONS);
super.setCredentialsMatcher(shaCredentialsMatcher);
}
/**
* 自定义方法:清除所有 授权缓存
*/
public void clearAllCachedAuthorizationInfo() {
if(getAuthorizationCache() != null){
getAuthorizationCache().clear();
}
}
/**
* 自定义方法:清除所有 认证缓存
*/
public void clearAllCachedAuthenticationInfo() {
if(getAuthenticationCache() != null){
getAuthenticationCache().clear();
}
}
/**
* 自定义方法:清除所有的 认证缓存 和 授权缓存
*/
public void clearAllCache() {
clearAllCachedAuthenticationInfo();
clearAllCachedAuthorizationInfo();
PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
super.clearCache(principals);
}
}
3、配置缓存与Cookie
@Configuration
public class ShiroConfig {
@Bean
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 集成缓存
*
* @return sessionManager
*/
@Bean("sessionManager")
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//设置session过期时间(单位:毫秒),默认为15分钟
sessionManager.setGlobalSessionTimeout(10000 * 60 * 1500);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
/**
* 1.配置Cookie对象
* 记住我的cookie:rememberMe
*
* @return SimpleCookie rememberMeCookie
*/
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//simpleCookie.setHttpOnly(true);
//单位(秒)1天
simpleCookie.setMaxAge(60 * 60 * 24);
return simpleCookie;
}
/**
* 2.配置cookie管理对象
*
* @return CookieRememberMeManager
*/
@Bean
public CookieRememberMeManager cookieRememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
@Bean("securityManager")
public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
// 自定义缓存实现
securityManager.setCacheManager(ehCacheManager());
securityManager.setSessionManager(sessionManager);
// 设置cookie管理
securityManager.setRememberMeManager(cookieRememberMeManager());
return securityManager;
}
/**
* shiro缓存管理器。需要添加到securityManager中
* @return cacheManager
*/
@Bean
public EhCacheManager ehCacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:shiro/ehcache-shiro.xml");
return cacheManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
/*重要,设置自定义拦截器,当访问某些自定义url时,使用这个filter进行验证*/
Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
// 如果map里面key值为authc,表示所有名为authc的过滤条件使用这个自定义的filter
// map里面key值为LoginFilter,表示所有名为LoginFilter的过滤条件使用这个自定义的filter,具体见下方
filters.put("myFilter", new LoginFilter());
shiroFilter.setFilters(filters);
shiroFilter.setLoginUrl("/login");
// shiroFilter.setSuccessUrl("/sys/index");
shiroFilter.setUnauthorizedUrl("/403");
Map<String, String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/vue-admin-template/**", "anon");
filterMap.put("/templates/test/**", "anon");
filterMap.put("/base/product/**", "anon");
filterMap.put("/static/**", "anon");
filterMap.put("/login/**", "anon");
filterMap.put("/logout", "logout");
filterMap.put("/druid/**", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/pay/wx/notify", "anon");
filterMap.put("/pay/wx/notifyRefund", "anon")Shiro安全框架简介以及身份验证
简单易用的Apache shiro框架,以及复杂完整的springboot security安全框架