java

阅读更多

spring-context-shiro.xml

 



      
      
  
     
    

   
       
     
      
     
   

      
      
      
      
        
         
      
     
     
    
  
      
      
      
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
              
                /mydemo/login=anon  
                /mydemo/getVerifyCodeImage=anon  
                /main**=authc  
                /user/info**=authc 
                /admin/**=user  
              
          
      
  
      
      
  

 

spring-context.xml




	Spring Configuration

	
	
	
	
	
	
	

	
 	
    
        
        
    
    
    
    
        
        
    
    
    
	
		
	
	
	
	
    
    
	
	 
	    
	    
	    
		
		
		
		
		
	
	
	
	
	
	

 

spring-mvc.xml

  
  
      
      
      
      
      
      
  
      
      
      
          
          
      
  
      
      
  
      
      
      
      
      
      
  
      
      
      
          
              
                  
                WEB-INF/error_fileupload  
                  
                WEB-INF/500  
              
          
      
    
       
      
      
     
     
    	
      
      
         
      

 

web.xml

  
  
      
  
  
  
      
    
      
        contextConfigLocation  
        classpath*:/spring-context*.xml  
      
  
    
      
        org.springframework.web.util.IntrospectorCleanupListener  
      
      
      
      
      
        org.springframework.web.context.ContextLoaderListener  
      
  
  
    
        logbackConfigLocation
        classpath:logback.xml
     -->
  
      
      
      
      
        SpringEncodingFilter  
        org.springframework.web.filter.CharacterEncodingFilter  
          
            encoding  
            UTF-8  
          
          
            forceEncoding  
            true  
          
      
      
        SpringEncodingFilter  
        /*  
      
      
      
      
      
      
      
        shiroFilter  
        org.springframework.web.filter.DelegatingFilterProxy  
          
              
            targetFilterLifecycle  
            true  
          
      
      
        shiroFilter  
        /*  
      
  
      
      
        SpringMVC  
        org.springframework.web.servlet.DispatcherServlet  
          
            contextConfigLocation  
            classpath*:/spring-mvc*.xml  
          
      
      
        SpringMVC  
        /  
      
  
      
      
  
    
      
      
     
      
        login.jsp  
      
    

 

MyRealm.java

package com.wzy.realm;  
  

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
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.UsernamePasswordToken;
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.springframework.beans.factory.annotation.Autowired;

import com.wzy.domain.Permission;
import com.wzy.domain.Role;
import com.wzy.domain.RolePermission;
import com.wzy.domain.User;
import com.wzy.service.PermissionService;
import com.wzy.service.RolePermissionService;
import com.wzy.service.RoleService;
import com.wzy.service.UserService;
import com.wzy.util.PrincipalUtils;  
  
/** 
 * 自定义的指定Shiro验证用户登录的类 
 * @see 在本例中定义了2个用户:papio和big,papio具有admin角色和admin:manage权限,big不具有任何角色和权限 
 * @create
 * @author
 */  
@SuppressWarnings("restriction")
public class MyRealm extends AuthorizingRealm {  
	
	@Autowired
	private transient UserService userService ;
	@Resource
	private RoleService roleService ;
	@Resource
	private PermissionService permissionService;
	@Resource
	private RolePermissionService rolePermissionService ;
    /** 
     * 为当前登录的Subject授予角色和权限 
     * @see 经测试:本例中该方法的调用时机为需授权资源被访问时 
     * @see 经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例中默认并未启用AuthorizationCache 
     * @see 个人感觉若使用了Spring3.1开始提供的ConcurrentMapCache支持,则可灵活决定是否启用AuthorizationCache 
     * @see 比如说这里从数据库获取权限信息时,先去访问Spring3.1提供的缓存,而不使用Shior提供的AuthorizationCache 
     */  
    @Override  
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){  
        //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()  
      String currentUsername = (String)super.getAvailablePrincipal(principals);  
      List roleList = new ArrayList();  
      List permissionList = new ArrayList();  
      //从数据库中获取当前登录用户的详细信息  
      User user = userService.getByUserName(currentUsername);  
      if(null != user){  
          //实体类User中包含有用户角色的实体类信息  
    	  Role role = roleService.get(user.getRoleId()) ;
          if(null!=role){  
              //获取当前登录用户的角色  
              roleList.add(role.getCode());  
              List list = rolePermissionService.getByRoleId(role.getUuid()) ;
              //实体类Role中包含有角色权限的实体类信息  
              for (RolePermission rolePermission : list) {
            	  if(!StringUtils.isEmpty(rolePermission.getCode())) {
            		  permissionList.add(rolePermission.getCode()) ;
            	  }
              }
          }  
      }else{  
          throw new AuthorizationException();  
      }  
      //为当前用户设置角色和权限  
      SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();  
      simpleAuthorInfo.addRoles(roleList);  
      simpleAuthorInfo.addStringPermissions(permissionList); 
        //若该方法什么都不做直接返回null的话,就会导致任何用户访问/admin/listUser.jsp时都会自动跳转到unauthorizedUrl指定的地址  
        //详见applicationContext.xml中的的配置  
        return simpleAuthorInfo;  
    }  
  
      
    /** 
     * 验证当前登录的Subject 
     * @see 经测试:本例中该方法的调用时机为LoginController.login()方法中执行Subject.login()时 
     */  
    @Override  
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {  
        //获取基于用户名和密码的令牌  
        //实际上这个authcToken是从LoginController里面currentUser.login(token)传过来的  
        //两个token的引用都是一样的,本例中是org.apache.shiro.authc.UsernamePasswordToken@33799a1e  
        UsernamePasswordToken token = (UsernamePasswordToken)authcToken;  
        System.out.println("验证当前Subject时获取到token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));  

        User user = userService.getByUserName(token.getUsername()); 
	      System.out.println(user.getUserName());
	      if(null != user){  
	          AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), user.getRealName());  
	          this.setSession("session_user", user);
	          return authcInfo;  
	      }
	      return null ;
    }  
      
      
    /** 
     * 将一些数据放到ShiroSession中,以便于其它地方使用 
     * @see 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到 
     */  
    private void setSession(Object key, Object value){  
        Subject currentUser = PrincipalUtils.getSubject();  
        if(null != currentUser){  
            Session session = currentUser.getSession();  
            System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒");  
            if(null != session){  
                session.setAttribute(key, value);  
            }  
        }  
    }  
}

 接下来控制层先要进行登录验证,然后为当前登录的Subject授予角色和权限 ,登录验证和授予角色和权限都在MyRealm类中执行。

控制层登录验证代码:

package com.wzy.controller;  
  
  
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import com.wzy.domain.Permission;
import com.wzy.domain.Role;
import com.wzy.domain.RolePermission;
import com.wzy.domain.User;
import com.wzy.service.PermissionService;
import com.wzy.service.RolePermissionService;
import com.wzy.service.RoleService;
import com.wzy.service.UserService;
import com.wzy.util.PrincipalUtils;
import com.wzy.util.SessionUtils;  

@SuppressWarnings("restriction")
@Controller  
@RequestMapping("/user")  
public class UserManageController {  

	@Resource
	private RoleService roleService ;
	@Resource
	private PermissionService permissionService;
	@Resource
	private UserService userService ;
	@Resource
	private RolePermissionService rolePermissionService ;
	/** 
     * 用户登录 
     */  
    @RequestMapping(value="/login", method=RequestMethod.POST)  
    public String login(HttpServletRequest request){  
        String resultPageURL = InternalResourceViewResolver.FORWARD_URL_PREFIX + "/";  
        String username = request.getParameter("username");  
        String password = request.getParameter("password");  

        UsernamePasswordToken token = new UsernamePasswordToken(username, password);  
        token.setRememberMe(true);  
        System.out.println("为了验证登录用户而封装的token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));  
        //获取当前的Subject  
        Subject currentUser = PrincipalUtils.getSubject();  
        try {  
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查  
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应  
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法  
             System.out.println("对用户[" + username + "]进行登录验证..验证开始");  
            currentUser.login(token);  
            System.out.println("对用户[" + username + "]进行登录验证..验证通过");  
            SessionUtils.getSessionAttr("session_user") ;
            resultPageURL = "main";  
        }catch(UnknownAccountException uae){  
            System.out.println("对用户[" + username + "]进行登录验证..验证未通过,未知账户");  
            request.setAttribute("message_login", "未知账户");  
        }catch(IncorrectCredentialsException ice){  
            System.out.println("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证");  
            request.setAttribute("message_login", "密码不正确");  
        }catch(LockedAccountException lae){  
            System.out.println("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定");  
            request.setAttribute("message_login", "账户已锁定");  
        }catch(ExcessiveAttemptsException eae){  
            System.out.println("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多");  
            request.setAttribute("message_login", "用户名或密码错误次数过多");  
        }catch(AuthenticationException ae){  
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景  
            System.out.println("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下");  
            ae.printStackTrace();  
            request.setAttribute("message_login", "用户名或密码不正确");  
        }  
        
        //新建所有的权限
        if(username.equals("admin")) {
        	User user = userService.getByUserName(username) ;
        	Role role = roleService.get(user.getRoleId()) ;
        	List list = permissionService.findAll() ;
        	List rp = new ArrayList() ;
        	for (Permission permission : list) {
				RolePermission rolePermission = new RolePermission() ;
				rolePermission.setRoleId(role.getUuid());
				rolePermission.setPermissionId(permission.getUuid());
				rolePermission.setCode(role.getCode()+":"+permission.getCode());
				rp.add(rolePermission) ;
			}
        	rolePermissionService.insertBatch(rp);
        }
        
        //验证是否登录成功  
        if(currentUser.isAuthenticated()){  
            System.out.println("用户[" + username + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");  
        	currentUser.hasRole("admin") ;
        }else{  
            token.clear();  
        }  
        return resultPageURL;  
    }  
      
    @RequiresPermissions("admin:query")
    @RequestMapping("/main")
    public String main() {
    	/*Subject currentUser = PrincipalUtils.getSubject();  
    	 if(!currentUser.hasRole("admin")) {
    		 System.out.println("用户对应的不是该角色");
    		 throw new RuntimeException("该用户没有该权限") ;
    	 }*/
    	return "login" ;
    }
      
    /** 
     * 用户登出 
     */  
    @RequestMapping("/logout")  
    public String logout(HttpServletRequest request){  
         SecurityUtils.getSubject().logout();  
         return InternalResourceViewResolver.REDIRECT_URL_PREFIX + "/";  
    }  
}

 

控制层就可以通过@RequiresPermissions()进行权限访问了

 

你可能感兴趣的:(java,shiro,session)