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 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 params;
private String clientDigest;
public StatelessToken(String username,Map 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";
}
returnnull;
}
}
然后进行shiro的配置文件部分内容:
这里的sessionManager的sessionValidationSchedulerEnabled属性一定得设置为false。
【shiro的一点记录(三)】这样就可以使用啦。这里没有列出对用户名和消息生成消息摘要的类,基本上就是对属性加密的一个类。
推荐阅读
- 框架|Mybatis的一级缓存和二级缓存
- Android|OkHttp 异步网络请求流程
- SpringBoot的基础搭建
- 框架|springboot把配置实体和配置文件关联
- Android|Android网络框架-OkHttp使用
- util|POI兼容读取Excel2003和Excel2007
- 分享mybatis的常见面试题
- 高并发系统三大利器之缓存
- 算法和数据结构|【回溯法】批处理作业调度问题