- 開發環境配置
- eclipse Mars.2 Release (4.5.2)
- maven 3.3.9
- jdk 1.8.0_171
- os win10
- 環境搭建
- 創建maven工程
- 編輯pom.xml
<!-- 繼承說明:這裏繼承SpringBoot提供的父工程 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.4.0</version> </dependency> </dependencies>
- 創建包結構
- ShiroConfig配置類
@Configuration public class ShiroConfig { /** * ShiroFilterFactoryBean 處理攔截資源文件問題。設置對應的過濾條件和跳轉條件 */ @Bean public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必須設置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登錄成功後要跳轉的鏈接 shiroFilterFactoryBean.setSuccessUrl("/index"); // 未授權界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); // 自定義攔截器 Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>(); // 限制同一帳號同時在線的個數。 // filtersMap.put("kickout", kickoutSessionControlFilter()); shiroFilterFactoryBean.setFilters(filtersMap); // 權限控制map. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 授權資源,只有登錄了才能訪問,並且有該對應權限的用戶纔可以訪問 // 例如:從數據庫獲取動態的權限 // filterChainDefinitionMap.put("/add", "perms[權限添加]"); // 從數據庫獲取 /* * List<SysPermissionInit> list = sysPermissionInitService.selectAll(); * * for (SysPermissionInit sysPermissionInit : list) { * filterChainDefinitionMap.put(sysPermissionInit.getUrl(), * sysPermissionInit.getPermissionInit()); } */ // <!-- 過濾鏈定義,從上向下順序執行,一般將 /**放在最爲下邊 -->:這是一個坑呢,一不小心代碼就不好使了; // <!-- authc:所有url都必須認證通過纔可以訪問; anon:所有url都都可以匿名訪問--> // logout這個攔截器是shiro已經實現好了的。 // filterChainDefinitionMap.put("/js/**","anon"); // filterChainDefinitionMap.put("/login/**","anon"); // filterChainDefinitionMap.put("/logout","logout"); // filterChainDefinitionMap.put("/**","authc"); // 遊客,開發權限 filterChainDefinitionMap.put("/guest/**", "anon"); // 用戶,需要角色權限 "user" filterChainDefinitionMap.put("/user/**", "roles[user],perms[retrieve]"); // 管理員,需要角色權限 "admin" filterChainDefinitionMap.put("/admin/**", "roles[admin],perms[create]"); // 開放登陸接口 filterChainDefinitionMap.put("/login", "anon"); // 其餘接口一律攔截 // 主要這行代碼必須放在所有權限設置的最後,不然會導致所有 url 都被攔截 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 權限管理,配置主要是Realm的管理認證 * * @return */ @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設置realm. securityManager.setRealm(myShiroRealm()); // 自定義緩存實現 // securityManager.setCacheManager(cacheManager()); // 自定義session管理 // securityManager.setSessionManager(sessionManager()); // 注入記住我管理器; securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } /** * 密碼匹配憑證管理器 */ @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName(PasswordUtils.ALGORITHM_NAME); hashedCredentialsMatcher.setHashIterations(PasswordUtils.HASH_ITERATIONS);// 散列的次數,比如散列兩次,相當於 // md5(md5("")); return hashedCredentialsMatcher; } /** * 自定義的Realm,將自己的驗證方式加入容器 */ @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); // 設置密碼憑證匹配器 // myShiroRealm.setCredentialsMatcher(matcher); return myShiroRealm; } /** * cookie對象; * * @return */ public SimpleCookie rememberMeCookie() { // 這個參數是cookie的名稱,對應前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); // <!-- 記住我cookie生效時間30天 ,單位秒;--> simpleCookie.setMaxAge(2592000); return simpleCookie; } /** * cookie管理對象;記住我功能 * * @return */ public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); // rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位) cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } /** * 開啓shiro aop註解支持. 使用代理方式;所以需要開啓代碼支持;否則@RequiresRoles等註解無法生效 * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( DefaultSecurityManager 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; } }
- 自定義驗證方式類MyShiroRealm
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private IUserService iUserService;
/**
* 授權用戶權限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 獲取用戶
// User user = (User)SecurityUtils.getSubject().getPrincipal();
// 獲取登錄用戶名
String name = (String) principalCollection.getPrimaryPrincipal();
// 查詢用戶名稱
User user = iUserService.getByUsername(name);
// 添加角色和權限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role role : iUserService.getRoles(user.getId())) {
// 添加角色
info.addRole(role.getMark());
for (Permission permission : iUserService.getRolePermissions(role.getId())) {
// 添加權限
info.addStringPermission(permission.getMark());
}
}
return info;
}
/**
* 驗證用戶身份
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 獲取用戶賬號
String username = token.getPrincipal().toString();
User user = iUserService.getByUsername(username);
//密碼進行加密處理
String password = user.getPassword();
if (password != null) {
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, // 認證通過後,存放在session,一般存放user對象
password, // 用戶數據庫中的密碼
getName()); // 返回Realm名
return authenticationInfo;
} else {
return null;
}
}
}
- 配置LoginController
@RestController
public class LoginController {
@Autowired
private IUserService userService;
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(String username, String password) {
// 從SecurityUtils裏邊創建一個 subject
Subject subject = SecurityUtils.getSubject();
// 在認證提交前準備 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 執行認證登陸
subject.login(token);
//根據權限,指定返回數據
String role = userService.getRoles("110").get(0).getMark();
if ("user".equals(role)) {
return "歡迎登陸";
}
if ("admin".equals(role)) {
return "歡迎來到管理員頁面";
}
return "權限錯誤!";
}
}
7.配置UserController類
@RestController
@RequestMapping("/user")
public class UserController {
//註解的使用
@RequiresRoles("user")
@RequiresPermissions("retrieve")
@RequestMapping(value = "/retrieve")
public String retrieve(){
return "Retrieve success!";
}
}
8.配置AdminController類
@RestController
@RequestMapping("/admin")
public class AdminController {
//註解的使用
@RequiresRoles("admin")
@RequiresPermissions("create")
@RequestMapping(value = "/create")
public String create(){
return "Create success!";
}
}
9.編寫啓動代碼
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
10.瀏覽器運行 http://localhost:8080/user/retrieve 會跳轉到 http://localhost:8080/login 因爲訪問時會先跳轉到/login進行校驗,但是沒有帶用戶名和密碼所以校驗失敗
11.瀏覽器運行http://localhost:8080/login?username=lc&password=1314 驗證成功
12.瀏覽器運行http://localhost:8080/admin/create 訪問權限驗證成功
13.瀏覽器運行http://localhost:8080/user/retrieve 因爲訪問權限驗證不通過所以會跳轉到配置的403 http://localhost:8080/403 但是沒有配置403請求處理所以404
ps:沒有配置數據庫請求服務層裏的數據都是造的