最近學了shiro安全框架流程,在這里梳理一下shiro的工作流程和一些代碼,方便以后使用的時候,能快速找到對應的代碼。
要使用這個shiro框架,還要新建兩張表 t_authority(權限表)和t_role_authority(角色權限表)
1.先在porm.xml中引入四個jar包,分別是shiro-core(shiro核心包)、shiro-web(shiro服務包)、shiro-spring(shiro和spring整合包)和shiro-ehcache(shiro緩存包)
<shiro.version>1.3.2</shiro.version
<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-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
2.在web.xml中配置filter(攔截器),攔截所有URL請求路徑。
<!-- shiro過濾器定義 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 該值缺省為false,表示生命周期由SpringApplicationContext管理,設置為true則表示由ServletContainer管理 --> <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.在application.xml(spring.xml)中配置Realm、安全管理器和shiro過濾器
<!-- 配置自定義Realm -->
<bean id="myRealm" class="com.oracle.shiro.UserRealm">
<property name="credentialsMatcher" >
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<!-- Shiro過濾器 核心-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,這個屬性是必須的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 身份認證失敗,則跳轉到登錄頁面的配置 -->
<property name="loginUrl" value="/login.html"/>
<property name="successUrl" value="/index.jsp"/>
<!-- 權限認證失敗,則跳轉到指定頁面 -->
<property name="unauthorizedUrl" value="/login.htmls"/>
<!-- Shiro連接約束配置,即過濾鏈的定義 -->
<property name="filterChainDefinitions">
<value>
<!-- /candidate/admin/**=authc -->
<!--anon 表示匿名訪問,不需要認證以及授權-->
/login.htmls = anon
/css/** = anon
/dist/** = anon
/js/** = anon
/user/loginIn.dodo = anon
/user/reg.dodo = anon
/res/** = anon
/logout = logout
<!--authc表示需要認證 沒有進行身份認證是不能進行訪問的-->
/**=authc
<!-- /student=roles[teacher]
/teacher=perms["user:create"]
--> </value>
</property>
</bean>
4.新建一個UserRealm類,該類的路徑對應(3)中的自定義的Realm配置的class路徑。
package com.oracle.shiro;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.StringUtils;
import com.oracle.model.User;
import com.oracle.service.RoleService;
import com.oracle.service.UserService;
public class UserRealm extends AuthorizingRealm {
// 用戶對應的角色信息與權限信息都保存在數據庫中,通過UserService獲取數據
@Resource
private UserService userService;
/**
* 提供用戶信息返回權限信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String currentUsername = (String)super.getAvailablePrincipal(principals);
List<String> roleList = null; //用來存放角色碼的集合
List<String> permissionList = null; //用來存放當前用戶的權限碼
//從數據庫中獲取當前登錄用戶的詳細信息
User user = userService.findUserByUsername(currentUsername);
if(null != user){
permissionList = userService.getPermissions(user.getId());//根據當前登錄用戶的id,獲取當前用戶的權限碼
roleList = userService.findRolesByUserId(user.getId());//根據當前用戶的id,獲取當前用戶的角色碼
}else{
throw new AuthorizationException();
}
//為當前用戶設置角色和權限
SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
simpleAuthorInfo.addRoles(roleList);//把用戶角色碼交給shiro
simpleAuthorInfo.addStringPermissions(permissionList);//把用戶權限碼交給shiro
return simpleAuthorInfo;
}
/**
* 提供賬戶信息返回認證信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.findUserByUsername(username);
if (user == null) {
// 用戶名不存在拋出異常
throw new UnknownAccountException();
}else{
ByteSource salt = ByteSource.Util.bytes(user.getSalt());//鹽值
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getName(),
user.getPassWord(),salt,getName());
SecurityUtils.getSubject().getSession().setAttribute("CURRENT_USER", user);
return authenticationInfo;
}
}
}
注:在(4)中從數據庫中獲取用戶信息的方法,比較簡單,就不粘貼出來了(service->dao層->mapper.xml)
5.在spring-mvc.xml中配置,開啟shiro注解,shiro才能被正式使用。
<!-- 開啟Shiro注解 -->
<!-- 保證實現了Shiro內部lifecycle函數的bean執行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<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>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthorizedException">
/unauthorized
</prop>
</props>
</property>
</bean>
登錄、注冊的controller中的代碼:
package com.oracle.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.oracle.model.User;
import com.oracle.service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
private static Logger log = Logger.getLogger(UserController.class);
@Autowired
private UserService userServiceNew;
@RequestMapping("/reg")
@ResponseBody
public Map reg(User user) {
Map<String,Object> map = new HashMap<String,Object>();
// user.setPassWord(JavaUtilMD5.MD5(user.getPassWord()));
Random rd = new Random();
int salt = rd.nextInt(100000);
SimpleHash sh = new SimpleHash("MD5", user.getPassWord(),ByteSource.Util.bytes(salt+"") , 1024);
user.setPassWord(sh.toString());
user.setSalt(salt+"");
int i = userServiceNew.save(user);
if(i>0) {
map.put("code", 200);
}else {
map.put("code", 500);
}
return map;
}
@RequestMapping("/loginIn")
public String loginIn(User user,HttpSession session) {
if(user == null) {//
return "redirect:index.html?loginCode=500";
}else {
Subject subject = SecurityUtils.getSubject();
// 判斷當前用戶是否登陸
if (subject.isAuthenticated() == false) {
UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassWord());
try {
subject.login(token);
// Session session = subject.getSession();
// user = (SysUser) session.getAttribute(Constants.CURRENT_USER);
// session.setAttribute("SESSION_USERNAME", user.getId() + "");
// // 根據用戶id查找用戶角色
// SysUser u = this.findUserByUserId(user.getId());
// session.setAttribute("u", u);
return "index";
} catch (Exception e) {
// 這里將異常打印關閉是因為如果登錄失敗的話會自動拋異常
e.printStackTrace();
// model.addAttribute("error", "用戶名或密碼錯誤");
return "index";
}
} else {
// Session session = getSession();
// user = (SysUser) session.getAttribute(Constants.CURRENT_USER);
// session.setAttribute("SESSION_USERNAME", user.getId() + "");
return "index";
}
}
}
@Autowired
HttpServletRequest request;
@RequestMapping("/LoginInfo")
@ResponseBody
public Object Logininfo() {
HttpSession httpSession=request.getSession();
Object map=httpSession.getAttribute("CURR_USER");
return map;
}
@RequestMapping("/findPageData")
@ResponseBody
public Object findPageData(Integer page,Integer rows) {
Integer startIndex = (page-1)*rows;
Map<String,Object> map = new HashMap<String,Object>();
map.put("startIndex", startIndex);
map.put("rows", rows);
List<User> users = userServiceNew.findPageData(map);
map.put("rows", users);
map.put("total", userServiceNew.findTotleSize());
return map;
}
@RequestMapping("/findAllUser")
@ResponseBody
public Object findAllUser() {
return userServiceNew.findAllUser();
}
@RequestMapping("/user")
public String user() {
return "user";
}
@RequestMapping("/userSave")
@ResponseBody
public Map userSave(User user) {
Map<String,Object> map = new HashMap<String,Object>();
int i = userServiceNew.save(user);
if(i>0) {
map.put("code", 200);
}else {
map.put("code", 500);
}
return map;
}
@RequestMapping("/userUpdate")
@ResponseBody
public Map userUpdate(User user) {
Map<String,Object> map = new HashMap<String,Object>();
int i = userServiceNew.update(user);
if(i>0) {
map.put("code", 200);
}else {
map.put("code", 500);
}
return map;
}
@RequestMapping("/userDelete")
@ResponseBody
public Map userDelete(User user) {
Map<String,Object> map = new HashMap<String,Object>();
int i = userServiceNew.delete(user.getId());
if(i>0) {
map.put("code", 200);
}else {
map.put("code", 500);
}
return map;
}
@RequestMapping("/CurrUserMenu")
@ResponseBody
public Map<String,Object> findCurrUserMenu(){
User user = (User)SecurityUtils.getSubject().getSession().getAttribute("CURRENT_USER");
List<Map<String,Object>> menuList = userServiceNew.findCurrMenu(user.getId());
Map<String,Object> map = new HashMap<String,Object>();
map.put("code", 100);
map.put("msg", "");
Map<String,Object> m = new HashMap<String,Object>();
m.put("children", menuList);
map.put("extend", m);
return map;
}
}
