shiro的两种认证过程

介绍两种比较常见的认证方法。适用于不同的场景

1、传统的认证 (适用于客户端、服务器端直接跳转页面的情况)

java后台能直接跳转的应用

配置如下:

application.xml中配置


	
		
		
		
		
		
        
	        
	        	
	        	
	            
	        
        
		
			
				/Captcha.jpg = anon
				/styles/** = anon
				/Captcha.jpg = anon
				/login/timeout = anon
				/login = authc
				/logout = logout
		    	/** = user
		 	
		
	


在java controller中配置

@Controller
@RequestMapping("/login")
public class LoginController {
	private static final String LOGIN_PAGE = "login";

	@RequestMapping(method = RequestMethod.GET)
	public String login(HttpServletRequest request) {
		return LOGIN_PAGE;
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String fail(String username,Map map, HttpServletRequest request) {

		String msg = parseException(request);
		
		map.put("msg", msg);
		map.put("username", username);
		
		return LOGIN_PAGE;
	}
	
	private String parseException(HttpServletRequest request) {
		String error = (String) request
				.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
		String msg = "其他错误!";
		if (error != null) {
			if ("org.apache.shiro.authc.UnknownAccountException".equals(error))
				msg = "未知帐号错误!";
			else if ("org.apache.shiro.authc.IncorrectCredentialsException"
					.equals(error))
				msg = "密码错误!";
			else if ("com.ketayao.security.shiro.IncorrectCaptchaException"
					.equals(error))
				msg = "验证码错误!";
			else if ("org.apache.shiro.authc.AuthenticationException"
					.equals(error))
				msg = "认证失败!";
			else if ("org.apache.shiro.authc.DisabledAccountException"
					.equals(error))
				msg = "账号被冻结!";
		}
		return "登录失败," + msg;
	}
	
}

以上的认证过程为:  

当在login.jsp 中 点击登录按钮,POST请求 /login      {username:"admin", password: "123456"}

    首先 进入 /login = authc 认证过滤器,将请求来的username password 在自定义的Realm进行认证,

    如果认证通过,则走

    如果认证失败,走继续走/login 的action,也就是LoginController中的fail()方法

如果上面的认证过程不是很明白,则可以参考源码。


看一下AdviceFilter的源码吧:

public abstract class AdviceFilter extends OncePerRequestFilter{
    public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        Exception exception = null;
        try {

            boolean continueChain = preHandle(request, response);
            if (log.isTraceEnabled()) {
                log.trace("Invoked preHandle method.  Continuing chain?: [" + continueChain + "]");
            }

            if (continueChain) {
                executeChain(request, response, chain);
            }

            postHandle(request, response);
            if (log.isTraceEnabled()) {
                log.trace("Successfully invoked postHandle method");
            }

        } catch (Exception e) {
            exception = e;
        } finally {
            cleanup(request, response, exception);
        }
    }
}

当前面所讲的认证通过后,boolean continueChain= preHandle(request,response);

continueChain会返回false。

所以下面的代码是不执行的。

if (continueChain) {

               executeChain(request, response, chain);

}

但是认证失败时,返回true,就会执行自己的action操作。



2、自定义认证(适用于ajax类的json操作,非web应用)

第二种配置相比之下就较灵活 ,首先配置applicationContext-shiro.xml


	
		
		 
        
	        
	        	
	        	
	                 
	        
        
		
			
				/ = anon
				/views/** = anon
				/styles/** = anon
				/login = anon
				/login/timeout = anon
				/Captcha.jpg = anon
				/logout = logout
		    	        /** = user
		 	
		
	
咋看一下,几乎没什么区别,主要的一个区别是:/login = authc 这句配置没有了。也就是说,认证的过程由自己控制了。

先看一下LoginController中的代码

        @RequestMapping(value = "/login", method = RequestMethod.POST)
	public @ResponseBody String login(String username,String password,HttpServletRequest request) {

		UsernamePasswordToken token = new UsernamePasswordToken( username, password );
		token.setRememberMe(true);
		Subject currentUser = SecurityUtils.getSubject();
		
		String messageCode = MessageCode.LOGIN_SUCCESS  ;
		
		try {
		    currentUser.login(token);
		} catch ( UnknownAccountException ex ) { 
			messageCode = MessageCode.LOGIN_ACCOUNT_ERROR;
			ex.printStackTrace();
		} catch ( IncorrectCredentialsException ex ) {
			messageCode = MessageCode.LOGIN_PASSWORD_ERROR;
			ex.printStackTrace();
		} catch ( LockedAccountException ex ) { 
			messageCode = MessageCode.LOGIN_ACCOUNT_LOCKED;
			ex.printStackTrace();
		} catch ( ExcessiveAttemptsException ex ) {
			messageCode = MessageCode.LOGIN_EXCESSIVE_ERROR;
			ex.printStackTrace();
		} catch ( AuthenticationException ex ) {
			messageCode = MessageCode.LOGIN_AUTHTICATION_FAIL;
			ex.printStackTrace();
		}
		
		if(currentUser.isAuthenticated()){
			return new ResultVO<>(messageCode).toString();	//认证成功
		}else{
			return new ResultVO<>(ResultVO.FAILURE,messageCode).toString();  //认证失败
		}
		
		
	}

因为在applicationContext-shiro.xml中已经配置了 /login=anon, 所以就直接进入了 LoginController的 login() 方法。通过自己调用 currentUser.login(token)

来进行验证,然后 在try{} catch(){} 语句中,得到相应的错误。

根据下面的判断,来返回json数据给前端

		if(currentUser.isAuthenticated()){
			return new ResultVO<>(messageCode).toString();	//认证成功
		}else{
			return new ResultVO<>(ResultVO.FAILURE,messageCode).toString();  //认证失败
		}
前端就能根据返回的json数据,做出自己的选择。也就实现了 前后台的隔离。

与第一种验证方法还是有些不同,第一种方法 是后台进行逻辑跳转。

而且第二种方法也能适用于非web应用的程序。





你可能感兴趣的:(shiro)