shiro權限架構
1.shiro依賴包
<!-- shiro的支援包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.4.0</version>
<type>pom</type>
</dependency>
<!-- shiro與Spring的內建包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
2.在web.xml中配置shiro代理過濾器
<!-- Spring與shiro內建:需要定義一個shiro過濾器(這是一個代理過濾器,它會到spring的配置中找一個名稱相同的真實過濾器) -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>\/*</url-pattern>
</filter-mapping>
3.spring配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置安全管理者-->
<bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">
<!--配置安全管理者的權限資料-->
<property name="realm" ref="myRealm"/>
</bean>
<bean class="com.wal.aisell.shiro.MyRealm" id="myRealm">
//設定密碼的比對方式
<property name="credentialsMatcher">
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--設定加密方式-->
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="10"/>
</bean>
</property>
</bean>
<!--配置shiro生命周期方法-->
<bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor" id="lifecycleBeanPostProcessor"/>
<!--配置使用shiro的注解,但是必需配置在Spring Ioc容器中Shiro bean的生成周期方法-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!--配置真實的shiro過濾器 必須與web.xml中的代理過濾器名字一緻-->
<bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" id="shiroFilter">
<property name="securityManager" ref="securityManager"/>
<!--登入時的url,如果沒有登入會自動跳到該頁面-->
<property name="loginUrl" value="/login"/>
<!--登入成功後跳到的頁面-->
<property name="successUrl" value="/main"/>
<!--沒有權限是跳到這個頁面-->
<property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
<!--配置哪些資源被保護,哪些資源需要權限
anon:不需要登入也可以通路相應的權限
authc:需要權限才能通路
** :所有檔案及其子檔案
-->
<!--<property name="filterChainDefinitions">
<value>
/s/login.jsp=anon
/login=anon
/s/main.jsp=perms[user:*]
\/**=authc
</value>
</property>-->
<!--資源權限map-->
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"/>
<!--引入自定義權限過濾器-->
<property name="filters">
<map>
<entry value-ref="myPermissionAuthorizationFilter" key="wal"></entry>
</map>
</property>
</bean>
<!--引入自定義權限過濾器bean-->
<bean class="com.wal.aisell.shiro.MyPermissionAuthorizationFilter" id="myPermissionAuthorizationFilter"/>
<!--在bean中設定哪些資源需要放行,哪些資源需要權限-->
<bean class="com.wal.aisell.shiro.FilterChainDefinitionMapBuilder" id="filterChainDefinitionMapBuilder"></bean>
<bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder"
factory-method="creatFilterChainDefinitionMap"/>
</beans>
資源權限MapfilterChainDefinitionMapBuilder
public class FilterChainDefinitionMapBuilder {
@Autowired
private IPermissionService permissionService;
public Map<String,String> creatFilterChainDefinitionMap(){
LinkedHashMap<String, String> map = new LinkedHashMap<>();
/* /s/login.jsp=anon
/login=anon
/s/main.jsp=perms[user:*]
*//**=authc*/
//靜态資源放行
map.put("/login","anon");
map.put("*.js","anon");
map.put("*.css","anon");
map.put("/css/**","anon");
map.put("/js/**","anon");
map.put("/easyui/**","anon");
map.put("/images/**","anon");
//從資料庫中讀出通路路徑所需要的權限
List<Permission> permissionList = permissionService.findAll();
permissionList.forEach(permission -> {
String url = permission.getUrl();
String sn = permission.getSn();
//這裡要改成自定義的權限過濾器對應的key值
map.put(url, "wal["+sn+"]");
});
map.put("//**","authc" );
return map;
}
}
自定義權限過濾器 根據使用者權限做相應處理
//複寫預設權限過濾器,使其支援ajax請求
public class MyPermissionAuthorizationFilter extends PermissionsAuthorizationFilter {
//這是請求沒有權限時處理的方法,預設是跳轉頁面,現在要加一個對ajax的處理
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = this.getSubject(request, response);
if (subject.getPrincipal() == null) {
this.saveRequestAndRedirectToLogin(request, response);
} else {
//先強轉成http請求,因為http請求才能獲得請求頭
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
String header = req.getHeader("X-Requested-With");
//ajax請求的标志XMLHttpRequest
if (header != null && "XMLHttpRequest".equals(header)){
//設定響應類型
resp.setContentType("text/json,charset=UTF-8");
//設定響應消息
resp.getWriter().print("{\"seccess\":false,\"msg\":\"沒有權限\"}");
}else {
String unauthorizedUrl = this.getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl)) {
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
WebUtils.toHttp(response).sendError(401);
}
}
}
return false;
}
}
自定義MyRealm 使用者身份認證和權限管理
public class MyRealm extends AuthorizingRealm {
//驗證角色和權限
@Autowired
private IPermissionService permissionService;
@Autowired
private IRoleService roleService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//拿到身份驗證成功後傳回的主題
Employee employee = (Employee)principalCollection.getPrimaryPrincipal();
//更具登入使用者得到該使用者的角色資訊
Set<Role> roles = roleService.findRolesByLoginUser(employee);
Set<String> rolesStr = new HashSet<>();
Set<String> permissionAll = new HashSet<>();
roles.forEach(role -> {
//根據登入使用者的角色資訊,拿到使用者權限
Set<String> permission = permissionService.findPermissionByRole(role);
permissionAll.addAll(permission);
String sn = role.getSn();
rolesStr.add(sn);
});
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setStringPermissions(permissionAll);
authorizationInfo.setRoles(rolesStr);
//Set<String> permission = permissionService.findPermissionByLoginUser(employee);
//SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//authorizationInfo.setStringPermissions(permission);
return authorizationInfo;
}
//驗證身份
@Autowired
private IEmployeeService employeeService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//authenticationToken對應subject.login(token) 中的token
String username = (String)authenticationToken.getPrincipal();
String password = employeeService.findPasswordByusername(username);
Employee employee = employeeService.findByusername(username);
if (password==null){
return null;
}
//設定鹽值
ByteSource salt = ByteSource.Util.bytes(MD5Utils.SALT);
//密碼比對成功後 ,subject.getPrincipal獲得的就是employee,如果你寫的是usernamesubject獲得的就是username
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(employee, password,salt, getName());
return authenticationInfo ;
}