Spring整合Shiro安全框架 ##
----------
### **Shiro框架的配置**
1. 導入jar包,若是使用了Maven,引入座標便可(項目配置文件中已經引入)
2. 配置Spring整合Shiro的核心過濾器,核心filter,一個filter至關於10個filter
* 代碼以下
<!-- Shiro Security filter filter-name這個名字的值未來還會在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整合Shiro框架,須要配置
* 建立applicationContext-shiro.xml的配置文件,引入約束
* 在applicationContext配置文件引入<import resource="classpath:spring/applicationContext-shiro.xml"></import>
4. 配置DelegatingFilterProxy過濾器,經過shiroFilter名稱去IOC的容器中查找對象,配置該對象(配置具體的規則)
<!-- filter-name這個名字的值來自於web.xml中filter的名字 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--登陸頁面 -->
<property name="loginUrl" value="/index.jsp"></property>
<!-- 登陸成功後-->
<property name="successUrl" value="/home.action"></property>
<property name="filterChainDefinitions">
<!-- /**表明下面的多級目錄也過濾 -->
<value>
/index.jsp* = anon
/home* = anon
/sysadmin/login/login.jsp* = anon
/sysadmin/login/loginAction_logout* = anon
/login* = anon
/logout* = anon
/components/** = anon
/css/** = anon
/img/** = anon
/js/** = anon
/plugins/** = anon
/images/** = anon
/js/** = anon
/make/** = anon
/skin/** = anon
/stat/** = anon
/ufiles/** = anon
/validator/** = anon
/resource/** = anon
/** = authc
/*.* = authc
</value>
</property>
</bean>
5. 配置安全管理器,須要配置
* 配置安全管理器
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 必需要注入自定義Realm域,至少提供一個 -->
<property name="realm" ref="authRealm"/>
</bean>
* 配置自定義Realm域,準備提供數據
<!-- 配置自定義Realm域 -->
<bean id="authRealm" class="cn.Mr.Neng.jk.shiro.AuthRealm">
<!-- 注入密碼比較器 -->
<property name="credentialsMatcher" ref="passwordMatcher"/>
</bean>
* 注意:該Realm域尚未建立,須要本身手動建立,Realm類必需要繼承AuthorizingRealm類,這是編寫Realm域的規範。就至關於過濾器要實現Filter接口一個道理。
* 有2個抽象方法必須添加實現,具體的代碼以下
/**
* 自定義Realm域
* @author Administrator
*/
public class AuthRealm extends AuthorizingRealm{
@Resource(name="userService")
private UserService userService;
/**
* 受權
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
return null;
}
/**
* 認證
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
return null;
}
}
* 配置密碼比較器的類,密碼比較器的類也須要本身手動建立,須要繼承SimpleCredentialsMatcher類,重寫doCredentialsMatch方法進行密碼比較
* 具體的代碼以下
/**
* 密碼比較器
* @author Administrator
*/
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{
/**
* 用於進行密碼比較的
*/
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
return super.doCredentialsMatch(token, info);
}
}
* 配置以下
<bean id="passwordMatcher" class="cn.Mr.Neng.jk.shiro.CustomCredentialsMatcher"/>
6. 測試shiro的配置文件
* 首先修改LoginAction類的login的方法,添加以下代碼
// 判斷用戶名是否爲空,若是爲空,跳轉到登陸頁面
if(UtilFuns.isEmpty(username)){
return LOGIN;
}
----------
### **Md5hash加密算法**
1. md5的加密
* 比較經常使用的加密算法,相對來講容易被破解
* 算法比較固定,密碼是123,使用md5加密,獲得的密文是固定的(202cb962ac59075b964b07152d234b70)!!
2. 採用shiro的Md5Hash算法進行加密
* 使用工具類Encrypt類
----------
### **登陸認證的代碼編寫**
1. 打開AuthRealm類,準備完成認證代碼的編寫。認證就是登陸功能,最疼密碼須要一致,先編寫密碼比較器
2. 打開CustomCredentialsMatcher類,準備編寫代碼
/**
* 密碼比較器
* @author Administrator
*/
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{
/**
* 用於進行密碼比較的
* token -- 表示從頁面傳過來的用戶名和密碼
* info -- 表示從數據庫中查詢到的密碼
*/
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
// 把token向下強轉成實現類
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 獲取密碼
String inputPwd = new String(upToken.getPassword());
// 對密碼加密
String md5Pwd = Encrypt.md5(inputPwd, upToken.getUsername());
// 獲取到數據庫中的密碼
String dbPwd = info.getCredentials().toString();
return super.equals(md5Pwd, dbPwd);
}
}
3. 打開AuthRealm類,完成認證的方法編寫,具體的代碼以下
/**
* 認證
* AuthenticationToken token 表示頁面傳過來的用戶名和密碼
* 邏輯:經過用戶名查詢數據庫,獲取到該用戶的密碼,封裝到AuthenticationInfo對象中,返回。
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 獲取到用戶名
final String username = upToken.getUsername();
// 建立條件對象
Specification<User> spec = new Specification<User>() {
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get("userName").as(String.class), username);
}
};
// 經過用戶名查詢數據庫,查詢數據庫,查詢數據
List<User> list = userService.find(spec);
// 判斷
if(list != null && list.size() > 0){
// 獲取到user對象
User user = list.get(0);
// 建立AuthenticationInfo對象
/**
* principal user對象
* credentials 密碼
* realmName 字符串,自定義的,realm的名稱
*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), "abc");
return info;
}
return null;
}
----------
### **編寫登陸的方法**
1. 搭建LoginAction,編寫login的登陸方法,具體代碼以下
public String login() throws Exception {
// 判斷
if(UtilFuns.isEmpty(username)){
return LOGIN;
}
try {
// 先獲取到Subject對象
Subject subject = SecurityUtils.getSubject();
// 建立UsernamePasswordToken對象,封裝用戶名和密碼
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 使用shiro框架進行校驗
subject.login(token);
// 獲取返回的結果
User user = (User) subject.getPrincipal();
// 存入到session中
ServletActionContext.getRequest().getSession().setAttribute(SysConstant.CURRENT_USER_INFO, user);
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
super.put("errorInfo", "用戶名或者密碼錯誤!!");
return "login";
}
}
----------
### **編寫退出的方法**
1. 具體的代碼以下
//退出
public String logout(){
//刪除session
session.remove(SysConstant.CURRENT_USER_INFO);
SecurityUtils.getSubject().logout();
return "logout";
}
----------
用戶受權的代碼編寫
1. 受權功能:認證經過後的用戶,所擁有的權限。
2. shiro框架提供和權限有關的標籤庫
* <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
* <shiro:hasPermission name="系統首頁">,判斷認證經過後的用戶,是否擁有系統首頁的權限?若是該用戶擁有系統首頁權限,把標籤中間的內容顯示到頁面上。
3.打開AuthRealm類,完成受權的方法編寫,具體的代碼以下
/**
* 受權
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
// 從AuthenticationInfo中獲取到用戶對象
User user = (User) pc.fromRealm(this.getName()).iterator().next();
List<String> list = new ArrayList<String>();
// 繼續操做,經過對象導航的方式,獲取到該用戶下的角色,具備哪些權限
Set<Role> roles = user.getRoles();
// 遍歷,獲取到每個角色對象
for (Role role : roles) {
// 經過角色對象獲取到該角色具備的權限
Set<Module> modules = role.getModules();
for (Module module : modules) {
list.add(module.getName());
}
}css
//這個SimpleAuthorizationInfo 對象封裝的是受權信息,之後要判斷某個方法或者按鈕是否擁有權限,只須要用spring提供的對應標籤便可(Permissions)
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(list);
return info;
}web
注意:此隨筆是本人在網上借鑑某某機構所得。算法