Shiro(一)——Shrio增加token验证

项目需求:Shrio增加token验证。
需求分析:
1.Shrio的认证方式的流程:

登录Controller中,根据输入的账号和密码创建token,然后调用subject.login(token)方法,subject会委托给securityManager,由securityManager再执行login方法。

由ModularRealmAuthenticator调用realm的doGetAuthenticationInfo进行认证。如果不正确则抛出异常执行onFailedLogin()

2.基于session的登录认证

在ShiroFilterFactoryBean中可以添加Filter来验证是否已登录。

isAccessAllowed方法通过subject.getPrincipal()是否为空来判断该subject是否已登录。
getSubject()是从当前线程得到绑定的subject

那subject是什么时候创建的呢?
ShiroFilterFactoryBean里就包含了AbStractShiroFilter,每次请求的时候都会执行doFilterInternal里的createSubject,如何跟session绑定的呢?放到sessionManage里再分析,这里简单略过。subject会根据context来生成,而context中则包含了session。

每次请求都会重新设置Session和Principals,看到这里大概就能猜到:如果是web工程,直接从web容器获取httpSession,然后再从httpSession获取Principals,本质就是从cookie获取用户信息,然后每次都设置Principal,这样就知道是哪个用户的请求,并只得到这个用户有没有人认证成功,–本质:依赖于浏览器的cookie来维护session的。
实现方法:1.创建一个自己的realm用于验证第三方的token,继承AuthorizingRealm,需要supports方法来支持自定义的token。

public class MyRealm extends AuthorizingRealm {

    public boolean supports(AuthenticationToken token) {
        return token instanceof GylToken;
    }

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        GylToken gylToken = (GylToken) token;
        //发送http请求验证
        //创建httpClient实例对象
        HttpClient httpClient = new HttpClient();
        // 设置httpClient连接主机服务器超时时间:15000毫秒
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(15000);
        // 创建GET请求方法实例对象
        GetMethod getMethod = new GetMethod("xxx");
        // 设置post请求超时时间
        getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 60000);
        //getMethod.addRequestHeader("Content-Type", "application/json");
        getMethod.setRequestHeader("token",(String) token.getCredentials());
        try{
            httpClient.executeMethod(getMethod);
            String result = getMethod.getResponseBodyAsString();
            JSONObject jsonObject=JSONObject.fromObject(result);
            Map map = (Map)jsonObject;
            if(map.get("flag")==null || (int)map.get("flag")!=1){
                throw new UnknownAccountException("token无效");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            getMethod.releaseConnection();
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo("test", gylToken.getPrincipal(), getName());
        return info;
    }
}

2.有了认证还不够,还要添加Filter来拦截获取Token

重写onAccessDenied方法,isAccessAllowed失败,走onAccessDenied方法判断如果token为空则走正常途径,如果token不为空则走executeLogin,再调用subject.login(token)走自定义realm的认证方法。

protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
    String token = getRequestToken((HttpServletRequest) servletRequest);
    if (StringUtils.isBlank(token)) {
        saveRequestAndRedirectToLogin(servletRequest, servletResponse);
        return false;
    }
    return executeLogin(servletRequest, servletResponse);

}

3.虽然这样已经满足了基本需求,但只能每次都走realm认证,没有用到shiro的核心完整的会话管理。

你可能感兴趣的:(Shiro(一)——Shrio增加token验证)