添加多个自定义的Realm实现类,定义你的认证和权限认证逻辑.这里演示代码为复制了一份CustomRealm2 .
这样的好处是当你的用户表不是一张表可以分别认证用户,比如学生表 教师表 分别都有账户密码 权限
步骤:
1.准备一个以上的自定义Realm类:
/授权和认证逻/
public class CustomRealm extends AuthorizingRealm {
@Autowired
UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println ("执行授权逻辑");
SimpleAuthorizationInfo simpleInfo = new SimpleAuthorizationInfo ( );
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal ( );
//之后在数据库查询他是什么角色 什么权限一一添加他们
System.out.println ("查询角色和权限:" + name);
List<String> listRoles = userService.listRoles (name);
// simpleInfo.addRoles (listRoles);直接添加多个角色或者forench添加
for (String role : listRoles) {
simpleInfo.addRole (role);
}
//添加角色下的权限 比如crud
List<String> listPermissions = userService.listPermissions (name);
System.out.println (listPermissions.size ( ));
simpleInfo.addStringPermissions (listPermissions);
//设置好权限返回
return simpleInfo;
}
@Override
protected SimpleAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
;
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (null == authenticationToken.getPrincipal ( )) {
return null;
}
//这里用于区分两个认证是否都可以加载
System.out.println ("执行认证逻辑2222222222222222" + getName ( ));
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取用户登陆的名
String name = token.getUsername ( );
//查出的密码和盐封装成User
User user = userService.getPwdByName (name);
if (null == user) {
//用户名不存在
return null;//抛出一个空的对象 抛出异常UnknowAccountException
}
//密码
String pwd = user.getPassword ( );
//盐
String salt = user.getSalt ( );
//真盐=name+salt
salt = name + salt;
//这里验证authenticationToken和simpleAuthenticationInfo的信息
return new SimpleAuthenticationInfo (name, pwd, ByteSource.Util.bytes (salt), getName ( ));
}
}
第二个:修改一下名字和打印语句来区分他们省略
2.ShiroConfig配置修改,添加Realm bean配置和多肉(Realm)认证策略
/*常用的过滤器
* anon:无认证
* authc:必须认证 登陆即可
* user: 使用记住我可以直接访问
* perms: 必须有资源权限 比如crud
* roles: 必须有角色权限
* */
@Configuration
public class ShiroConfig {
/**
* 创建自定义配置的Realm
*/
@Bean
CustomRealm myRealm() {
CustomRealm customRealm = new CustomRealm ( );
//注入加密算法
customRealm.setCredentialsMatcher (hashedCredentialsMatcher ());
return customRealm;
}
@Bean
CustomRealm2 myRealm2() {
CustomRealm2 customRealm = new CustomRealm2 ( );
//注入加密算法
customRealm.setCredentialsMatcher (hashedCredentialsMatcher ());
return customRealm;
}
//认证策略配置需要把realm集合配置进来这
@Bean
public ModularRealmAuthenticator authenticators(){
ModularRealmAuthenticator model=new ModularRealmAuthenticator ();
AllSuccessfulStrategy authenticationStrategy= new AllSuccessfulStrategy();
//最少一个成功验证 都失败则返回null
AtLeastOneSuccessfulStrategy atLeastOne=new AtLeastOneSuccessfulStrategy ();
//最先验证成功的那个返回,剩下的不验证 都失败则返回null
FirstSuccessfulStrategy first =new FirstSuccessfulStrategy ();
//添加策略属性为其中一个对象
List list= new ArrayList<Realm> ();
list.add (myRealm ());
list.add (myRealm2 ());
//多策略需要先把realm配置属性加进去
model.setRealms (list);
model.setAuthenticationStrategy (authenticationStrategy);
return model;
}
/**
* 创建DefaultWebSecurityManager管理器,使它管理自定义的Realm
*/
@Bean
DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager ( );
List list= new ArrayList<Realm> ();
//多realm配置通过以下获取
List list= new ArrayList<Realm> ();
list.add (myRealm ());
list.add (myRealm2 ());
//realm配置通过以下获取
manager.setRealms (list);
//自定义的Realm交给manager
// manager.setRealm (myRealm ( ));
//策略设置
manager.setAuthenticator (authenticators ());
// 自定义缓存实现 使用redis
// manager.setCacheManager(cacheManager ());
// 自定义session管理 使用redis
//manager.setSessionManager(SessionManager ());
// 使用记住我,注入配置
manager.setRememberMeManager(new RememberMeConfig ().rememberMeManager ());
return manager;
}
/**
*创建shiroFilterFactoryBean
* 关联一个securityManager ( )管理器
*/
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean ( );
bean.setSecurityManager (securityManager ( ));
//登陆页
bean.setLoginUrl ("/login");
//登陆成功后界面
bean.setSuccessUrl ("/index");
//未授权跳转到
bean.setUnauthorizedUrl ("/tip");
Map<String, String> map = new LinkedHashMap<> ( );
//anon是把限制权限改为无限制
//map.put ("/index", "anon");
//authc 登陆后可以访问
// map.put ("/**", "authc");
map.put ("/add", "authc");
//权限必须有addProduct才可以访问
map.put ("/update","perms[addProduct]");
//角色是admin 才可以访问超级管理员界面
map.put ("/admin","roles[admin]");
bean.setFilterChainDefinitionMap (map);
return bean;
}
/**用于ShiroDialect和thymeleaf标签配合使用*/
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect(){
return new ShiroDialect ();
}
/**
* 密码加密算法设置
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列的次数
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
};
}
两个要点:1. DefaultWebSecurityManager securityManager配置list属性
2.ModularRealmAuthenticator authenticators配置策略和list同上
最后发现一个问题: AtLeastOneSuccessfulStrategy策略是最少一个验证成功还是第一个验证成功策略.都会有一个问题,就是只要验证账号密码成功了,那么其他realm虽然账号密码验证失败但是也会将权限一起添加.
因为,不同的realm肯定是对不同表的验证,他们的账号必须不同.