Shiro 專案開發中第一次使用到,所以研究了一下,這裡
阿新 • • 發佈:2019-01-04
專案使用的是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; }