shiro的一点记录(三)

    shiro的无状态web集成。所谓无状态就是服务器端无状态,就是不保存会话。一般的会话机制的web应用,都是session机制来保存用户状态。无状态的web应用就是每次请求都带上相应的用户名进行登录。
    具体的实践就是:客户端传入秘钥和一个消息作为输入,他们声称相应消息摘要,秘钥是只有客户端和服务端知道的。访问的时候服务端对消息摘要进行验证。
   具体的实例如下:
  首先我们创建subject的工厂必须是不保存session的:
   
public class StatelessDefaultSubjectFactory extends DefaultWebSubjectFactory {

    @Override
    public Subject createSubject(SubjectContext context)
    {
        context.setSessionCreationEnabled(false);
        return super.createSubject(context);
    }
}
   我们自定义一个无状态的Filter:
public class StatelessAuthcFilter extends AccessControlFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        //客户端生成的消息摘要
        String clientDigest=servletRequest.getParameter("digest");
        //客户端传入的用户身份
        String username=servletRequest.getParameter("username");
        //客户端的参数列表
        String param1=servletRequest.getParameter("param1");
        String param2=servletRequest.getParameter("param2");
        Map<String,String> params=new HashMap<>();
        params.put("param1",param1);
        params.put("param2",param2);
        //生成无状态Token
        StatelessToken token=new StatelessToken(username,params,clientDigest);
        try {
            getSubject(servletRequest,servletResponse).login(token);
        }
        catch (Exception e) {
            e.printStackTrace();
            onLoginFail(servletResponse);
        }
        return false;
    }
    private void onLoginFail(ServletResponse response) throws IOException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        httpResponse.getWriter().write("login error");
    }
}
     shiro框架没有提供专门的无状态的token,我们自己定义一个:
public class StatelessToken implements AuthenticationToken {
    private String username;
    private Map<String, ?> params;
    private String clientDigest;

    public StatelessToken(String username,  Map<String, ?> params, String clientDigest) {
        this.username = username;
        this.params = params;
        this.clientDigest = clientDigest;
    }。。。。。此处省略set和get代码
    自定义无状态的realm:
 
public class StatelessRealm extends AuthorizingRealm {
    @Autowired
    private IMememberService memberService;

    @Override
    public boolean supports(AuthenticationToken token) {
        //仅支持StatelessToken类型的Token
        return token instanceof StatelessToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = (String) principalCollection.getPrimaryPrincipal();
        Member user = memberService.findByUsername(username);
       // System.out.println(user);
        if (user != null) {
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            return authorizationInfo;
        } else throw new IncorrectCredentialsException();
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        StatelessToken statelessToken = (StatelessToken) token;
        String username = statelessToken.getUsername();
        String key = getKey(username);//根据用户名获取密钥(和客户端的一样)
        //在服务器端生成客户端参数消息摘要
        String serverDigest = HmacSHA256Utils.digest(key, statelessToken.getParams());
        System.out.println(statelessToken.getClientDigest());
        System.out.println(serverDigest);
        //然后进行客户端消息摘要和服务器端消息摘要的匹配
        return new SimpleAuthenticationInfo(
                username,
                serverDigest,
                getName());
    }
    /**
     * 获取秘钥,此处是硬编码的一个
     *
     * @param username
     * @return
     */
    private String getKey(String username) {

       if("admin".equals(username))
       {
           return "dadadswdewq2ewdwqdwadsadasd";
        }
      return  null;
    }
}
   然后进行shiro的配置文件部分内容:
 <!--statelessReealm-->
      <bean id="statelessRealm" class="com.supuy.sps.realm.StatelessRealm">
        <property name="cachingEnabled" value="false"/>
      </bean>
      <!--statelessReealm subject工厂-->
      <bean id="subjectFactory" class="com.supuy.sps.realm.factory.StatelessDefaultSubjectFactory"></bean>

        <!--statelessFilter-->
       <bean id="statelessFilter" class="com.supuy.sps.realm.filter.StatelessAuthcFilter"></bean>

   这里的sessionManager的sessionValidationSchedulerEnabled属性一定得设置为false。

   这样就可以使用啦。这里没有列出对用户名和消息生成消息摘要的类,基本上就是对属性加密的一个类。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章