shiro的两种认证过程

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

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

java后台能直接跳转的应用

配置如下:

application.xml中配置

<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<!-- 这个是用户未登录,会直接跳转到/login。 服务器端会让客户端重定向到 /login请求。 -->
		<property name="loginUrl" value="/login" />
		<!-- 用户认证通过,则同样通知客户端重定向到 /index 请求。 -->
		<property name="successUrl" value="/index" />
        <property name="filters">
	        <map>
	        	<!-- 
	        	<entry key="authc" value-ref="baseFormAuthenticationFilter"/>
	        	-->
	        	<!-- 是否启用验证码检验 -->
	            <entry key="authc" value-ref="captchaFormAuthenticationFilter"/>
	        </map>
        </property>
		<property name="filterChainDefinitions">
			<value>
				/Captcha.jpg = anon
				/styles/** = anon
				/Captcha.jpg = anon
				/login/timeout = anon
				/login = authc
				/logout = logout
		    	/** = user
		 	</value>
		</property>
	</bean>


在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<String, Object> 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进行认证,

    如果认证通过,则走 <property name="successUrl" value="/index" />

    如果认证失败,走继续走/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

<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login" /> 
        <property name="filters">
	        <map>
	        	<!-- 
	        	<entry key="authc" value-ref="baseFormAuthenticationFilter"/>
	        	-->
	        	<!-- 是否启用验证码检验 -->
	                <!-- <entry key="authc" value-ref="captchaFormAuthenticationFilter"/> --> 
	        </map>
        </property>
		<property name="filterChainDefinitions">
			<value>
				/ = anon
				/views/** = anon
				/styles/** = anon
				/login = anon
				/login/timeout = anon
				/Captcha.jpg = anon
				/logout = logout
		    	        /** = user
		 	</value>
		</property>
	</bean>
咋看一下,几乎没什么区别,主要的一个区别是:/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();<span>	</span>//认证成功
		}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();<span>	</span>//认证成功
		}else{
			return new ResultVO<>(ResultVO.FAILURE,messageCode).toString();  //认证失败
		}
前端就能根据返回的json数据,做出自己的选择。也就实现了 前后台的隔离。

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

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





  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值