shiro

apache shiro 是一个轻量级的身份验证与授权框架,与spring security 相比较,简单易用,灵活性高,springboot本身是提供了对security的支持,毕竟是自家的东西。springboot暂时没有集成shiro,这得自己配。

shiro 内置过滤器

本文实现:

本文实现从数据库读取用户信息,获取当前用户的权限或角色,通过配置文件过滤用户的角色或权限。拥有相应的角色或者相应的权限的用户可以访问相应的url。

数据库设计

springboot集成shiro 实现权限控制(转)_spring

1. 添加依赖
  <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.2.5</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.2.5</version></dependency><dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>1.2.1</version></dependency>


2. 添加shiro 配置



package com.us.shiro;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.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;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 javax.servlet.Filter;import java.util.LinkedHashMap;import java.util.Map;
/**
* shiro配置类
* Created by cdyoue on 2016/10/21.
*/@Configurationpublic class ShiroConfiguration {
/**
* LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
* 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
* 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
*/@Bean(name = "lifecycleBeanPostProcessor")public 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();
securityManager.setRealm(shiroRealm());// 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<>();
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]");//用户为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@ConditionalOnMissingBeanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);return defaultAAP;
}
/**
* AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,
* 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
aASA.setSecurityManager(securityManager());return aASA;
}


}


3. 添加Realm 验证
package com.us.shiro;

import com.us.bean.Permission;
import com.us.bean.Role;
import com.us.bean.User;
import com.us.dao.PermissionDao;
import com.us.dao.UserDao;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Created by cdyoue on 2016/10/21.
*/

public class ShiroRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
private UserDao userService;
@Autowired
private PermissionDao permissionService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("doGetAuthorizationInfo+"+principalCollection.toString());
User user = userService.getByUserName((String) principalCollection.getPrimaryPrincipal());


//把principals放session中 key=userId value=principals
SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()),SecurityUtils.getSubject().getPrincipals());

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//赋予角色
for(Role userRole:user.getRoles()){
info.addRole(userRole.getName());
}
//赋予权限
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.getByUserName(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. 添加controller
package com.us.controller;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;import java.util.Map;

/**
* Created by cdyoue on 2016/10/21.
* 登陆控制器
*/@RestControllerpublic class LoginController {private Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping(value = "/login", method = RequestMethod.POST)public String login(
@RequestParam(value = "username", required = true) String userName,@RequestParam(value = "password", required = true) String password,@RequestParam(value = "rememberMe", required = true, defaultValue = "false") boolean rememberMe
) {
logger.info("==========" + userName + password + rememberMe);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
token.setRememberMe(rememberMe);
try {
subject.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();// rediect.addFlashAttribute("errorText", "您的账号或密码输入错误!");return "{\"Msg\":\"您的账号或密码输入错误\",\"state\":\"failed\"}";
}return "{\"Msg\":\"登陆成功\",\"state\":\"success\"}";
}
@RequestMapping("/")@ResponseBodypublic String index() {return "no permission";
}
}


此处代码不全,只是写了springboot 整合的主要类,如果需要全部代码请移步。。。

源码:​​https://github.com/527515025/springBoot​