shiro安全框架的使用流程
最近学了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; } }