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); }

【Shiro(一)——Shrio增加token验证】3.虽然这样已经满足了基本需求,但只能每次都走realm认证,没有用到shiro的核心完整的会话管理。

    推荐阅读