springboot+shiro+vue實作權限管理
- 一 功能簡介:
-
- 1 介紹:
- 二 開始接入:
- 1 資料庫設計
-
- 2 導入依賴
- 3 ShiroConfiguration : 設定攔截
- 4 MyShiroRealm: 使用者權限認證
- 5 LoginService: 使用者登入/退出
- 6 權限使用
- 7 權限permission編碼
一 功能簡介:
1 介紹:
Apache Shiro是Java的一個安全架構。對比另一個安全架構Spring Sercurity,它更簡單和靈活。 Shiro可以幫助我們完成:認證、授權、加密、會話管理、Web內建、緩存等 2 shiro架構: 對于一個好的架構,從外部看來應該具有非常簡單易于使用的API,且API契約明确;從内部來看的話,其應該有一個可擴充的架構,即非常容易插入使用者自定義實作,因為任何架構都不能滿足所有需求。
二 開始接入:
1 資料庫設計
manager:role 關系 n:n
role:permission 關系 n:n
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPB10dBRVTwUEVNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5YjMyIzMyETM5ITNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2 導入依賴
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
3 ShiroConfiguration : 設定攔截
private String APP = ""; //項目字首 - 過濾攔截的時候使用
/**
* 開啟Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP掃描使用Shiro注解的類,并在必要時進行安全邏輯驗證
* 配置以下兩個bean(DefaultAdvisorAutoProxyCreator(可選)和AuthorizationAttributeSourceAdvisor)即可實作此功能
* 為了可以使用@RequiresPermissions标簽
* 必須放在最前面
*
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
//加入注解的使用,不加入這個注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//将自己的驗證方式加入容器
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
//權限管理,配置主要是Realm的管理認證
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//Filter工廠,設定對應的過濾條件和跳轉條件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<String, String>();
/**
* 基于DefaultFilter
anon:所有url都都可以匿名通路;
authc: 需要認證才能進行通路;
user:配置記住我或認證通過可以通路;
*/
//登出
map.put(APP+ "/logout", "logout");
//對所有使用者認證
//不攔截
map.put(APP+ "/index.html", "anon");
map.put(APP+ "/v1/login/**", "anon");
//攔截
map.put(APP+ "/page/intercept/index.html", "authc");
map.put(APP+ "/page/intercept/**", "authc");
//權限放行
map.put(APP+ "/page/intercept/dog3.jpg", "perms[permission:operlog_read]");
map.put(APP+ "/swagger-ui.html", "perms[permission:permission_write]");
//登入
shiroFilterFactoryBean.setLoginUrl(APP+ "/page/login.html"); //攔截後跳轉到此頁面
//首頁,登入之後跳轉
shiroFilterFactoryBean.setSuccessUrl(APP+ "/page/intercept/index.html"); // 登陸成功後跳轉的頁面
//錯誤頁面,認證不通過跳轉
shiroFilterFactoryBean.setUnauthorizedUrl(APP+ "/page/error.html"); //找不到的頁面指定跳轉
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
}
4 MyShiroRealm: 使用者權限認證
/**
* Created by zhiji on 2018/10/25.
* 進行權限資訊處理
*/
public class MyShiroRealm extends AuthorizingRealm {
// 用于使用者查詢
@Autowired
private ManagerService managerService;
/**
* 1 使用者通路URL的時候,查詢使用者權限,并綁定session
*
* @param authenticationToken
* @return 使用者資訊
* @throws AuthenticationException 捕獲異常,使用者是否登陸成功
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
long start = System.currentTimeMillis();
//加這一步的目的是在Post請求的時候會先進認證,然後在到請求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//擷取使用者資訊
String account = authenticationToken.getPrincipal().toString();
ShiroManagerGetOutDTO shiroManagerGetInDTO = managerService.selectByAccount(account);
if (shiroManagerGetInDTO == null) {
//這裡傳回後會報出對應異常
return null;
} else {
//這裡驗證authenticationToken和simpleAuthenticationInfo的資訊
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(account, shiroManagerGetInDTO.getPassword().toString(), getName());
long end = System.currentTimeMillis();
System.out.println(MyShiroRealm.class + " doGetAuthenticationInfo 登入認證 ---------- 總耗時 " + (end - start) + "ms");
return simpleAuthenticationInfo;
}
}
/**
* 2 使用者登陸的時候,資料庫查詢使用者資訊
* 增加角色
*
* @param principalCollection 傳遞過來的使用者資訊
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
long start = System.currentTimeMillis();
//1 擷取登入使用者名
String account = (String) principalCollection.getPrimaryPrincipal();
//2 查詢使用者名稱
ShiroManagerGetOutDTO manager = managerService.selectByAccount(account);
if (StringUtils.isEmpty(manager))
return null;
//3 添加角色和權限
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
ShiroRoleGetOutDTO role = manager.getShiroRoleGetInDTO();
if (StringUtils.isEmpty(role))
return null;
authorizationInfo.addRole(role.getName()); // 給使用者添加角色
List<ShiroPermissionGetOutDTO> permissions = role.getShiroPermissionGetInDTOList();
if (StringUtils.isEmpty(permissions) || permissions.size() <= 0)
return null;
for (ShiroPermissionGetOutDTO permission : permissions) {
authorizationInfo.addStringPermission(permission.getPermission()); // 添加使用者的權限
}
long end = System.currentTimeMillis();
System.out.println(MyShiroRealm.class + " doGetAuthorizationInfo ---------- 總耗時 " + (end - start) + "ms");
return authorizationInfo;
}
/**
* 清除所有使用者授權資訊緩存.
*/
public void clearCachedAuthorizationInfo(String principal) {
SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
clearCachedAuthorizationInfo(principals);
}
/**
* @return void 傳回類型
* @Title: clearAuthz
* @Description: TODO 清楚緩存的授權資訊
*/
public void clearAuthz() {
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
}
5 LoginService: 使用者登入/退出
public void login(ShiroLoginInDTO manager) {
ShiroLoginInOutDTO shiroLoginInOutInDTO = new ShiroLoginInOutDTO();
//添加使用者認證資訊
Subject subject = SecurityUtils.getSubject();
String account = manager.getAccount();
String password = AppMD5Util.MD5Repeated20(manager.getPassword()); //密碼統一使用MD5加密
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(manager.getAccount(), password);
subject.login(usernamePasswordToken);
subject.getSession().setTimeout(properties.getPermissionSessionTimeout()); //使用者有效登入時長: 1 hours
}
public void logout() {
Subject subject = SecurityUtils.getSubject();
subject.logout(); //使用者退出
subject.getSession().setTimeout(0);
}
6 權限使用
在controller層加入相應的标簽即可
@RequiresPermissions(value = {“permission:app_read”, “permission:app_write”},logical = Logical.OR )
@RequiresRoles(“admin”)
7 權限permission編碼
0:無
1:隻讀 read
2:讀寫 write
子產品碼 名稱 編碼 編碼字元串
10 子產品一
100 無權限
101 permission:permission_read
102 permission:permission_write
11 子產品二
110 無權限
111 permission:upload_read
112 permission:upload_write
12 子產品三
120 無權限
121 permission:publicity_read
122 permission:publicity_write
代碼待完善,持續更新。。。
1 将使用者token存儲到redis中、可以多節點部署
2 自定義token生成規則
3 shiro全局異常捕獲