目录
引入依赖:
<!-- 引入shiro框架的依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.2</version>
</dependency>
@Configuration
public class ShiroConfiguration {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器.权限控制map
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/login/**", "anon");
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/layui/**", "anon");
filterChainDefinitionMap.put("/regdologin/**", "anon");
filterChainDefinitionMap.put("/dologin/**", "anon");
// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问//-->
filterChainDefinitionMap.put("/**", "authc");
// 默认跳转到登陆页面
shiroFilterFactoryBean.setLoginUrl("/reglogin");
// shiroFilterFactoryBean.setLoginUrl("/login");
// 登陆成功后的页面
// shiroFilterFactoryBean.setSuccessUrl("/regindex");
// shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 核心的安全事务管理器CustomModularRealmAuthenticator
*
* @return
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置认证器
securityManager.setAuthenticator(customModularRealmAuthenticator());
List<Realm> realms = new ArrayList<>();
realms.add(myRegUserRealm());
realms.add(myUserRealm());
securityManager.setRealms(realms);
return securityManager;
}
/**
* 系统自带的Realm管理,主要针对多realm
*/
@Bean
public CustomModularRealmAuthenticator customModularRealmAuthenticator() {
CustomModularRealmAuthenticator customModularRealmAuthenticator = new CustomModularRealmAuthenticator();
customModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
return customModularRealmAuthenticator;
}
@Bean
public RegUserRealm myRegUserRealm() {
RegUserRealm myRegUserRealm = new RegUserRealm();
// myRegUserRealm.setCredentialsMatcher(hashedCredentialsMatcher());//设置解密规则
return myRegUserRealm;
}
@Bean
public SystemRealm myUserRealm() {
SystemRealm myUserRealm = new SystemRealm();
// myUserRealm.setCredentialsMatcher(hashedCredentialsMatcher());//设置解密规则
return myUserRealm;
}
/**
* 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Shiro生命周期处理器
*
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 自动创建代理
*
* @return
*/
@Bean
@DependsOn({ "lifecycleBeanPostProcessor" })
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
}
public class SystemRealm extends AuthorizingRealm {
// @Resource(name = "userServiceImp")
@Autowired
private UserService UserService;
@Autowired
private RoleService roleService;
@Autowired
private RoleMenuRelMapper roleMenuRelMapper;
@Autowired
private MenuMapper menuMapper;
private Logger logger = Logger.getLogger(SystemRealm.class);
@Override
public String getName() {
return LoginType.SYSTEM;
}
/**
* 提供用户信息,返回权限信息
*
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("---------------------------->授权认证:");
System.out.println("===================授权==================");
//校验当前用户类型是否正确,正确则进入处理角色权限问题,否则跳出
if (!principals.getRealmNames().contains(getName())) return null;
Set<String> roleSet = new HashSet<>();
Set<String> pemissionSet = new HashSet<>();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
Integer roleId = user.getRoleId();
Role role = roleService.findRoleById(roleId);
roleSet.add(role.getRoleName());
// 条件设置
RoleMenuRelExample example = new RoleMenuRelExample();
example.setOrderByClause("id desc");
RoleMenuRelExample.Criteria criteria = example.createCriteria();
if (roleId != null) {
criteria.andRoleIdEqualTo(roleId);
}
List<RoleMenuRel> roleMenuRels = roleMenuRelMapper.selectByExample(example);
for (RoleMenuRel roleMenuRel : roleMenuRels) {
Integer menuId = roleMenuRel.getMenuId();
Menu menu = menuMapper.selectByPrimaryKey(menuId);
// String UserMenuJson = mapper.writeValueAsString(UserMenu);
pemissionSet.add(menu.getPerms());
System.out.println(menu.getPerms());
}
// 将角色名称组成的Set提供给授权info
authorizationInfo.setRoles(roleSet);
// 将权限名称组成的Set提供给info
authorizationInfo.setStringPermissions(pemissionSet);
authorizationInfo.addRole(LoginType.SYSTEM);
return authorizationInfo;
}
/**
* 提供帐户信息,返回认证信息
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
logger.info("---------------------------->登陆验证:");
CustomizedToken token = (CustomizedToken) authenticationToken;
String userName = (String) authenticationToken.getPrincipal();
String password = new String((char[]) authenticationToken.getCredentials());
System.out.println("----------认证--------------");
User user = UserService.findUserByUserName(userName);
if (user == null) {
throw new UnknownAccountException("账号或密码不正确");
}
// 密码错误
if (!password.equals(user.getPassword())) {
throw new IncorrectCredentialsException("账号或密码不正确");
}
// 账号锁定
/*if (user.getState() == 0) {
throw new LockedAccountException("账号已被锁定,请联系管理员");
}*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
}
}
public class CustomizedToken extends UsernamePasswordToken {
private static final long serialVersionUID = -8994712492402637507L;
private String loginType;
public CustomizedToken() {
}
public CustomizedToken(final String username, final String password, final String loginType) {
super(username, password);
this.loginType = loginType;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
}
/**
* Description:全局shiro拦截分发realm
*/
public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
throws AuthenticationException {
System.out.println("CustomModularRealmAuthenticator=========认证器测试===============");
// 判断getRealms()是否返回为空
assertRealmsConfigured();
// 强制转换回自定义的MyLoginToken
CustomizedToken token = (CustomizedToken) authenticationToken;
// 找到当前登录人的登录类型
String loginType = token.getLoginType();
// 所有Realm
Collection<Realm> realms = getRealms();
// 找到登录类型对应的指定Realm
Collection<Realm> typeRealms = new ArrayList<Realm>();
for (Realm realm : realms) {
if (realm.getName().toLowerCase().contains(loginType))
typeRealms.add(realm);
}
// 判断是单Realm还是多Realm
if (typeRealms.size() == 1)
return doSingleRealmAuthentication(typeRealms.iterator().next(), token);
else
return doMultiRealmAuthentication(typeRealms, token);
}
}
@Controller
public class LoginController {
@Autowired
private UserService userService;
/**
* 登录
*
* @param session HttpSession
* @param username 用户名
* @param password 密码
* @return
*/
@RequestMapping(value = "/dologin")
@ResponseBody
public ServerResponse login(HttpSession session, @RequestParam(required = false) String username,
@RequestParam(required = false) String password) throws Exception {
// Shiro实现登录
// UsernamePasswordToken token = new UsernamePasswordToken(username,
// DigestUtils.md5Hex(password.getBytes()));
CustomizedToken token = new CustomizedToken(username, DigestUtils.md5Hex(password.getBytes()),LoginType.SYSTEM);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
// 把用户信息放到session里
User user = (User) subject.getPrincipal();
session.setAttribute("USER", user);
return ServerResponse.createBySuccessMessage("登录成功");
} catch (Exception e) {
e.printStackTrace();
return ServerResponse.createByErrorMessage("用户名或密码错误!");
}
}
}
-
jsp页面中引入标签:<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
-
在要控制的按钮上:<shiro:hasPermission name="billpolicy12"><li>计费策略</li></shiro:hasPermission>,其中name的值为相应权限,对应menu表里的perms字段。加上<shiro 标签,当前用户没权限,此按钮就隐藏不显示。
表中的perms为访问对应menu的权限,对应<shiro:hasPermission name="billpolicy12">里的name的值。
补充:单realm
1. 去掉自定义认证器、自定义token。
2. ShiroConfiguration 里 多reaml管理的部分改为:
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(myUserRealm());
return securityManager;
}
/**
* 自定义身份认证 realm;
*/
@Bean
public SystemRealm myUserRealm() {
return new SystemRealm();
}
3. 登录controller里token书写方式如下:
UsernamePasswordToken token = new UsernamePasswordToken(username,DigestUtils.md5Hex(password.getBytes()));
4. realm里微调。