Spring+Shiro+Token认证

首先引入Shiro的依赖包

   
    org.apache.shiro
    shiro-spring
    1.3.2
    

在我们的wed.xml中加入我们的shiro过滤器

		 
    	shiroFilter
    	org.springframework.web.filter.DelegatingFilterProxy
    
    
    
    	shiroFilter
    	/*
    

在Spring配置Shiro中的文件




		
		
		 
		
	  	
	  	
			
			
				/login/auth.do=anon
				
				/worker/**=aesToken,permissionOr[admin:staff_worker,admin:staff]
				/admin/**=aesToken,permissionOr[admin:staff_admin,admin:staff]
				/payConfig/**=aesToken
				/login/out.do=logout
				/**/**=aesToken,user
			
		
		
		
			 
	             
	             
	             
	        
		
	

	
		
		
	
			
	
	
	
		
		
	

	
		
	
		
		
	
	
	
	

	
	
	
	
	
	
	

自定义token类

import org.apache.shiro.authc.AuthenticationToken;
/**
 * Shiro中的Authentication,主要是检验token时使用
 */
public class AesToken implements AuthenticationToken{
	String token;
public AesToken(String token){
	this.token=token;
}
	public Object getPrincipal() {
		// TODO Auto-generated method stub
		return token;
	}

	public Object getCredentials() {
		// TODO Auto-generated method stub
		return token;
	}

}

创建自定义的shiro过滤器,当过滤器return true时返回到shiro权限认证的自定义realm中,把token放在头部,如果检查到没有token的话则视为未登录状态。有token的情况下会根据token来进行用户的权限认证。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.json.JSONObject;
import com.southgis.iznaer.base.ResponseConstant;
import com.southgis.iznaer.base.ResponseResult;
import com.southgis.iznaer.util.AesToken;

/**
 * 通过改过滤器跳到Realm中认证用户信息和权限信息
 * @author gyc
 * @date 2018-10-18
 */
public class AesFilter extends BasicHttpAuthenticationFilter  {
	/**
	 * 过滤方法
	 */
	protected boolean isAccessAllowed(ServletRequest request,
			ServletResponse response, Object object)  throws AuthenticationException  {
		String token=((HttpServletRequest) request).getHeader("token");
		ResponseResult jsonResult = new ResponseResult();
		//判断请求的请求头是否带上 "Token"
        if (token!=null) {
            try { 
            	AesToken m=new AesToken(token);
            	getSubject(request, response).login(m);
            	 return true;
            } catch (AuthenticationException e) {
                //token 错误
          	e.printStackTrace();
			jsonResult.setCode(ResponseConstant.TOKEN_FAIL_CODE);//返回失败的code
			jsonResult.setState(ResponseConstant.FAIL_STATE);//返回失败的state
			jsonResult.setDescription("token错误,或token已过期");
			jsonResult.setResults(null);
            JSONObject jsonObject=new JSONObject(jsonResult);
            responseOutWithJson(response,jsonObject.toString());
            return false;
            }
        }
        //如果请求头不存在 Token,则可能是执行登陆操作或者是游客状态访问,无需检查 token,直接返回 true
        return true;
	}
    /** 
     * 以JSON格式输出 
     * @param response 
     */  
    protected void responseOutWithJson(ServletResponse response,  
            Object responseObject) {  
        //将实体对象转换为JSON Object转换  
     //   JSONObject responseJSONObject = JSONObject.fromObject(responseObject);  
    	 HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    	 httpServletResponse.setCharacterEncoding("UTF-8");  
    	 httpServletResponse.setContentType("application/json; charset=utf-8");  
        PrintWriter out = null;  
        try {  
            out = httpServletResponse.getWriter();  
            out.append((String)responseObject);  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            if (out != null) {  
                out.close();  
            }  
        }  
    } 
    
}

以下两个也是自定的权限过滤器,功能类似shiro中的默认权限。

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

/**
 * 自定义权限过滤器,拥有多权限之一的用户可以通过
 * @author gyc
 * @date 2018-10-18
 */
public class PermissionOrFilter extends AuthorizationFilter {

	@Override
	protected boolean isAccessAllowed(ServletRequest req,
			ServletResponse resp, Object object) throws Exception {
		Subject subject = getSubject(req, resp);
		String[] permissions = (String[]) object;
		if (permissions == null || permissions.length == 0) {
			return true;
		}
		for (String permission : permissions) {
			if (subject.isPermitted(permission)) {
				return true;
			}
		}
		return false;
	}

}

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
/**
 * 自定义角色过滤器,拥有多角色之一的用户可以通过
 * @author gyc
 * @date 2018-10-18
 */
public class RolesOrFilter extends AuthorizationFilter {

	@Override
	protected boolean isAccessAllowed(ServletRequest req,
			ServletResponse resp, Object object) throws Exception {
		
		Subject subject = getSubject(req, resp);
		
		String[] roles = (String[]) object;
		
		if (roles == null || roles.length == 0) {
			return true;
		}

		for (String role : roles) {
			if (subject.hasRole(role)) {
				
				return true;
			}
		}
		return false;
	}

}

自定义Reaml,在上文中我们所设置的自定义的shiro过滤器AesFilter 通过后会跳到Reaml中根据我们的token来进行权限的认证和分配。

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class UserRealm extends AuthorizingRealm {
	User user=null;
	@Resource(name = "userServiceImpl")
	UserService userService;
	@Resource(name = "permissionServiceImpl")
	PermissionService permissionService;
	/**
	 * 必须重写此方法,不然会报错
	 */
	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof AesToken;
	}
	/**
     * 默认使用此方法进行用户名正确与否验证,错误抛出异常即可。
     */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException{
		   System.out.println("————身份认证方法————");
	        String token = (String) authenticationToken.getCredentials();
	        user=userService.findUserByToken(token);
    		if(this.user== null){
    			throw new AuthenticationException("token认证失败!");
    		}
    		return new SimpleAuthenticationInfo(token, token, getName());
		}
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("————权限认证————");
               permissionService.findPermissionByUser(user);
		Set permissionSet = new HashSet();
		for (Permission permission : permissions) {
			permissionSet.add(permission.getName());
		}
		info.setStringPermissions(permissionSet);
		//把permissionSet放入info,info成功return后就可以成功配置和认证权限
		return info;
	}
}

到这里我们的shiro配置算是配置完毕了。
配置完以后我们可以到刚刚配置关于shiro那一段的spring xml文件配置我们访问的路径所需要的权限。如下:

	  	
	  	
			
			
				/login/auth.do=anon
				
				/worker/**=aesToken,permissionOr[admin:staff_worker,admin:staff]
				/admin/**=aesToken,permissionOr[admin:staff_admin,admin:staff]
				/payConfig/**=aesToken
				/login/out.do=logout
				/**/**=aesToken,user
			
		

除了可以加入我们自定义的过滤器以外,我们还可以添加shiro默认的过滤器。

Filter 解释
anon 无参,开放权限,可以理解为匿名用户或游客
authc 无参,需要认证
logout 无参,注销,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl(); 设置的 url
authcBasic 无参,表示 httpBasic 认证
user 无参,表示必须存在用户,当登入操作时不做检查
ssl 无参,表示安全的URL请求,协议为 https
perms[user] 参数可写多个,表示需要某个或某些权限才能通过,多个参数时写 perms[“user, admin”],当有多个参数时必须每个参数都通过才算通过
roles[user] 参数可写多个,表示是某个或某些角色才能通过,多个参数时写 roles[“admin,user”],当有多个参数时必须每个参数都通过才算通过
rest[user] 根据请求的方法,相当于 perms[user:method],其中 method 为 post,get,delete 等
port[8081] 当请求的URL端口不是8081时,跳转到schemal://serverName:8081?queryString 其中 schmal 是协议 http 或 https 等等,serverName 是你访问的 Host,8081 是 Port 端口,queryString 是你访问的 URL 里的 ? 后面的参数

配置完后当用户访问的时候,访问的流程如下:

  1. AesFilter:判断用户是否带有token,若有进入Reaml
  2. UserRealm :通过token认证获取到User用户
  3. UserRealm :通过User用户拿到权限,进行权限认证。
  4. 通过如perms[user] 、permissionOr[admin:staff_worker]等过滤器。
  5. 成功访问地址

你可能感兴趣的:(Spring+Shiro+Token认证)