项目使用的是Maven
首先要在pom.xml中引入shiro依赖
<!-- shiro 权限 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-aspectj</artifactId> <version>${shiro.version}</version> </dependency>
然后,在spring-mvc.xml 文件中配置 整合
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><!-- shiro 开启事务注解 --> <property name="securityManager" ref="securityManager"></property> </bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><!-- shiro 安全管理器 --> <property name="realm" ref="loginRealm"></property> </bean> <bean id="loginRealm" class="com.yxb.user.controller.LoginRealm"></bean><!-- 自定义 loginRealm 处理登陆具体业务dai--> <!-- shiro 工厂bean配置 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"></property><!-- shiro的核心安全接口 --> <property name="loginUrl" value="/common/login"></property><!-- 要求登录时的连接 --> <!-- <property name="successUrl" value="/" ></property> --><!-- 登录成功后要跳转的连接(此处已经在登录中处理了) --> <property name="unauthorizedUrl" value="/common/unauth"></property><!-- 未认证时要跳转的连接 --> <!-- shiro连接约束配置 --> <property name="filterChainDefinitions"> <value> /index.jsp=anon /unauth.jsp=anon /user/login=anon /static/**=anon /robots.txt=anon /**=authc </value> </property> </bean>
自定义Loginrealm类,该类必须继承AuthorizingRealm类做爸爸,重写两个方法,一个是认证另一个授权
package com.yxb.user.controller; import com.yxb.user.domain.AdminUser; import com.yxb.user.service.UserService; import com.yxb.utils.log.UUIDUtil; import com.yxb.utils.shiro.TokenManager; 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.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.util.Set; /** * 定义权限管理器 */ public class LoginRealm extends AuthorizingRealm { @Autowired private UserService userService; // 定义logger Logger logger = LoggerFactory.getLogger("auth"); @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String uid = UUIDUtil.getOnlyOneCode(); Long userId = TokenManager.getUserId(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); logger.info("[用户授权](业务码:{}) : 用户 {} ,正在授权操作...", uid, TokenManager.getNickname()); //根据用户ID查询角色(role),放入到Authorization里。 Set<String> roles = userService.selectAdminRoles(userId); info.setRoles(roles); logger.info("[用户授权](业务码:{}) : 用户 {} ,授予:{} 角色成功!", uid, TokenManager.getNickname(), roles.toString()); //根据用户ID查询权限(permission),放入到Authorization里。 Set<String> permissions = userService.selectAdminPermissions(userId); logger.info("[用户授权](业务码:{}) : 用户 {} ,授予:{} 权限成功!", uid, TokenManager.getNickname(), permissions.toString()); info.setStringPermissions(permissions); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String uid = UUIDUtil.getOnlyOneCode(); // 1. 转化成用户名密码令牌 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // 2. 判断用户名密码的可用性 String userName = token.getUsername(); logger.info("[登录认证](业务码:{}) : 用户 {} ,正在登录验证...", uid, userName); if (userName != null && !"".equals(userName)) { // 3. 判断用户名密码的正确行 AdminUser adminUser = userService.loginForWeb(token.getUsername(), String.valueOf(token.getPassword())); if (adminUser == null) { logger.info("[登录认证](业务码:{}) : 用户 {} ,发生'帐号或密码不正确!'异常,登录失败", uid, userName); throw new IncorrectCredentialsException("帐号或密码不正确!"); } else { if (adminUser.getState() == 0) { logger.info("[登录认证](业务码:{}) : 用户 {} ,认证失败: 用户已经禁用", uid, userName); throw new DisabledAccountException("用户已被禁用!"); } logger.info("[登录认证](业务码:{}) : 用户 {} ,认证成功", uid, userName); return new SimpleAuthenticationInfo(adminUser, String.valueOf(token.getPassword()), getName()); } } else { logger.info("[登录认证](业务码:{}) : 用户 {} ,发生'用户名不可为空!'异常,登录失败", uid, userName); throw new IncorrectCredentialsException("用户名不可为空!"); } } }
登陆方法
/** * 用于用户登录 * * @param username * @param password * @param verifyCode * @return 错误信息 */ @PostMapping("/login") public String login(HttpServletRequest request, String username, String password, String verifyCode, boolean rememberMe) { String msg = "redirect:home/main"; try { AdminUser user = new AdminUser(); user.setUsername(username); user.setPassword(password); TokenManager.login(user, rememberMe); return msg; } catch (IncorrectCredentialsException e) { msg = "登录密码错误."; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } catch (ExcessiveAttemptsException e) { msg = "登录失败次数过多."; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } catch (LockedAccountException e) { msg = "帐号已被锁定."; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } catch (DisabledAccountException e) { msg = "帐号已被禁用."; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } catch (ExpiredCredentialsException e) { msg = "帐号已过期."; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } catch (UnknownAccountException e) { msg = "帐号不存在."; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } catch (UnauthorizedException e) { msg = "您没有得到相应的授权!"; return "redirect:/common/login?error=" + URLUtils.URLencoder(msg); } }
shiro的TokenManager
package com.yxb.utils.shiro; import com.yxb.user.domain.AdminUser; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.session.Session; public class TokenManager { /** * 获取当前登录的用户User对象 * @return */ public static AdminUser getToken() { AdminUser token = (AdminUser) SecurityUtils.getSubject().getPrincipal(); return token; } /** * 获取当前用户的Session * * @return */ public static Session getSession() { return SecurityUtils.getSubject().getSession(); } /** * 把值放入到当前登录用户的Session里 * * @param key * @param value */ public static void setVal2Session(Object key, Object value) { getSession().setAttribute(key, value); } /** * 从当前登录用户的Session里取值 * * @param key * @return */ public static Object getVal2Session(Object key) { return getSession().getAttribute(key); } /** * 获取验证码,获取一次后删除 * * @return */ public static String getYZM() { String code = (String) getSession().getAttribute("CODE"); getSession().removeAttribute("CODE"); return code; } /** * 判断是否登录 * * @return */ public static boolean isLogin() { return null != SecurityUtils.getSubject().getPrincipal(); } /** * 登录 * * @param user * @param rememberMe * @return */ public static AdminUser login(AdminUser user, Boolean rememberMe) { UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); token.setRememberMe(rememberMe); SecurityUtils.getSubject().login(token); return getToken(); } /** * 退出登录 */ public static void logout() { SecurityUtils.getSubject().logout(); } /** * 检查权限 * @param permissions */ public static void hasPermissions(String ...permissions){ SecurityUtils.getSubject().checkPermissions(permissions); } }
当用户登录成功之后,shiro安全框架就会将用户的信息存放在session中,你可以通过User user = (User) SecurityUtils.getSubject().getPrincipal();这句代码在任何地方任何时候都能获取当前登录成功的用户信息。
这也是TokenManager 中调用之处
/** * 登录 * * @param user * @param rememberMe * @return */ public static AdminUser login(AdminUser user, Boolean rememberMe) { UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); token.setRememberMe(rememberMe); SecurityUtils.getSubject().login(token); return getToken(); }
/** * 获取当前登录的用户User对象 * * @return */ public static AdminUser getToken() { AdminUser token = (AdminUser) SecurityUtils.getSubject().getPrincipal(); return token; }