1、先把shiro环境搭起来
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-webartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-ehcacheartifactId>
<version>1.3.2version>
dependency>
2、规定加密规则,并做一些测试数据
创建一个类ShiroUtil,封装这些操作
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import java.util.HashMap;
import java.util.Map;
public class ShiroUtil {
static final String SHA="SHA-1";
static final Integer COUNT=369;//加密次数
//生成测试数据
public static void main(String[] args) {
Map<String, String> map = encodePassword("123456");
System.out.println(map);
}
//生成混淆字符串(盐)
public static String generateSalt(){
SecureRandomNumberGenerator salt = new SecureRandomNumberGenerator();
return salt.nextBytes().toHex();
}
//加密
public static String encode(String input,String salt){
return new SimpleHash(SHA,input,salt,COUNT).toString();
}
//详细信息
public static Map<String,String> encodePassword(String input){
Map<String,String> map=new HashMap<>();
String salt=generateSalt();
String password = encode(input, salt);
map.put("salt",salt);
map.put("password(明文)",input);
map.put("password(密文)",password);
return map;
}
}
3、写一大堆Shiro的配置,封装在配置类里
import com.apesource.common.MyRealm;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
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.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//创建shiro自带的cookie对象
@Bean
public SimpleCookie sessionIdCookie(){
SimpleCookie simpleCookie = new SimpleCookie();
simpleCookie.setName("ShiroSession");
return simpleCookie;
}
//创建realm
@Bean
public MyRealm getRealm(){
return new MyRealm();
}
//创建会话管理器
@Bean
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(false);
sessionManager.setSessionIdCookieEnabled(true);
sessionManager.setSessionIdCookie(sessionIdCookie());
sessionManager.setGlobalSessionTimeout(3600000);
return sessionManager;
}
//创建安全管理器
@Bean
public SecurityManager defaultWebSecurityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getRealm());
securityManager.setSessionManager(sessionManager());
return securityManager;
}
/**
* 5.保证实现了Shiro内部lifecycle函数的bean执行
*/
@Bean(name = "lifecycleBeanPostProcessor")
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 6.开启对shior注解的支持
* AOP式方法级权限检查
* @DependsOn意思是我这个组件要依赖于另一个组件,也就是说被依赖的组件会比该组件先注册到IOC容器中
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
/**
* 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验
*/
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());
return authorizationAttributeSourceAdvisor;
}
//8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制
@Bean
public ShiroFilterFactoryBean shiroFilter() {
//1.创建过滤器工厂
ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
//2.设置安全管理器
filterFactory.setSecurityManager(defaultWebSecurityManager());
//3.通用配置(跳转登录页面,为授权跳转的页面)
filterFactory.setLoginUrl("/authentic_error");//跳转url地址
//4.设置过滤器集合
//key = 拦截的url地址
//value = 过滤器类型
Map<String,String> filterMap = new LinkedHashMap<>();
//key:请求规则 value:过滤器名称
filterMap.put("/xxx/login","anon");//当前请求地址可以匿名访问
filterMap.put("/xxx/*","authc");//当前请求地址必须认证之后可以访问
//在过滤器工程内设置系统过滤器
filterFactory.setFilterChainDefinitionMap(filterMap);
return filterFactory;
}
}
重点看第八个配置,如果用户还没有认证,就不能访问xxx目录下的其他地址。只有login可以登录。
4、认证登录,创建MyRealm继承AuthorizingRealm,重写类中的方法
//认证(authentic)
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取登录的用户名密码(username-password)
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//登录的用户的用户名
String username = token.getUsername();
System.out.println("登录用户:"+username);
//根据username去数据库查表,获得emp对象(emp的基本信息)
Employee employee = service.findEmpByUsername(username);
//查到emp的全部信息,包括用户的角色权限(多表联查)
Employee empData = service.findEmpAndRole(employee.getId());
System.out.println("数据库用户数据:"+empData.toString());
if(empData!=null){
System.out.println("数据库有这个数据");
SimpleAuthenticationInfo info =
new SimpleAuthenticationInfo(empData,empData.getPassword(),
ByteSource.Util.bytes(empData.getSalt()),this.getName());
System.out.println("登录用户:"+info);
return info;
}
return null;
}
/**
* @Description 自定义密码比较器
* @param
* @return
* bean标签 init-method属性
*/
@PostConstruct
public void initCredentialsMatcher() {
//指定密码算法
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher("SHA-1");
//指定迭代次数
hashedCredentialsMatcher.setHashIterations(369);
//生效密码比较器
setCredentialsMatcher(hashedCredentialsMatcher);
}
1、建立角色表、权限表、角色权限关系表、角色用户关系表,做五表联查
级联步骤:
http://t.csdn.cn/plVrn
2、MyRealm中重写doGetAuthorizationInfo方法
//授权(authorize)
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//1.获取已认证的用户数据(已经登录的用户)
Employee employee = (Employee) principalCollection.getPrimaryPrincipal();//得到唯一的安全数据
System.out.println("授权用户:"+employee);
//2.根据用户数据获取用户的权限信息(所有角色,所有权限)
Set<String> roles = new HashSet<>();//所有角色
Set<String> perms = new HashSet<>();//所有权限
for (Role role : employee.getRoleList()) {
roles.add(role.getRoleName());
for (Permission perm : role.getPermissionList()) {
//code中的字符串保存了权限信息,@RequiresPermissions("xxx")可用
perms.add(perm.getCode());
}
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(perms);
info.setRoles(roles);
return info;
}
3、在需要特定权限的方法上加注解:@RequiresPermissions(“权限”)