Shiro 是一个 Apache 下的一开源项目项目,旨在简化身份验证和授权。
spring,springMVC,maven,shiro
shiro的配置,通过maven加入shiro相关jar包
第一步.shiro的配置,通过maven加入shiro相关jar包
org.apache.shiro shiro-core 1.2.1 org.apache.shiro shiro-web 1.2.1 org.apache.shiro shiro-ehcache 1.2.1 org.apache.shiro shiro-spring 1.2.1
第二步.web.xml中添加shiro过滤器
contextConfigLocation
classpath:application-context-*.xml
org.springframework.web.context.ContextLoaderListener
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
CharacterEncodingFilter
/*
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
shiroFilter
/admin/*
back
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc.xml
back
*.action
Archetype Created Web Application
第3步. spring中对shiro配置
/images/** = anon
/js/** = anon
/styles/** = anon
/validatecode.jsp = anon
/admin/logout.do = logout
/welcome.jsp = user
/admin/index.do = user
/** = authc
在上面的配置中每次开启了sessionManager都会出问题在这里将它注释掉了。
其次,上面中的配置也是将credentialsMatcher没有加入了,这种方式适用于没有对密码进行处理的情况。
其中CustomRealm的配置是重点。
第4步.在上面的配置中每次开启了sessionManager都会出问题在这里将它注释掉了。
其次,上面中的配置也是将credentialsMatcher没有加入了,这种方式适用于没有对密码进行处理的情况。
其中CustomRealm的配置是重点。
第4步.自定义Realm编码
自定义Realm编码
CustomRealm如下:
public class CustomRealm extends AuthorizingRealm {
// 设置realm的名称
@Override
public void setName(String name) {
super.setName("customRealm");
}
@Autowired
private AdminUserService adminUserService;
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// token中包含用户输入的用户名和密码
// 第一步从token中取出用户名
String userName = (String) token.getPrincipal();
// 第二步:根据用户输入的userCode从数据库查询
TAdminUser adminUser = adminUserService.getAdminUserByUserName(userName);
// 如果查询不到返回null
if (adminUser == null) {//
return null;
}
// 获取数据库中的密码
String password = adminUser.getPassword();
/**
* 认证的用户,正确的密码
*/
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(adminUser, password, this.getName());
//MD5 加密+加盐+多次加密
//SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(adminUser, password,ByteSource.Util.bytes(salt), this.getName());
return authcInfo;
}
/**
* 授权,只有成功通过doGetAuthenticationInfo方法的认证后才会执行。
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 从 principals获取主身份信息
// 将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型),
TAdminUser activeUser = (TAdminUser) principals.getPrimaryPrincipal();
// 根据身份信息获取权限信息
// 从数据库获取到权限数据
TAdminRole adminRoles = adminUserService.getAdminRoles(activeUser);
// 单独定一个集合对象
List permissions = new ArrayList();
if (adminRoles != null) {
permissions.add(adminRoles.getRoleKey());
}
// 查到权限数据,返回授权信息(要包括 上边的permissions)
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
// 将上边查询到授权信息填充到simpleAuthorizationInfo对象中
simpleAuthorizationInfo.addStringPermissions(permissions);
return simpleAuthorizationInfo;
}
// 清除缓存
public void clearCached() {
PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
super.clearCache(principals);
}
}
第5步.缓存配置
ehcache.xml代码如下:
通过使用ehache中就避免第次都向服务器发送权限授权(doGetAuthorizationInfo)的请求。
6.自定义表单编码过滤器
CustomFormAuthenticationFilter代码,认证之前调用,可用于验证码校验
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {
// 原FormAuthenticationFilter的认证方法
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
// 在这里进行验证码的校验
// 从session获取正确验证码
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = httpServletRequest.getSession();
// 取出session的验证码(正确的验证码)
String validateCode = (String) session.getAttribute("validateCode");
// 取出页面的验证码
// 输入的验证和session中的验证进行对比
String randomcode = httpServletRequest.getParameter("randomcode");
if (randomcode != null && validateCode != null && !randomcode.equals(validateCode)) {
// 如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中
httpServletRequest.setAttribute("shiroLoginFailure", "randomCodeError");
// 拒绝访问,不再校验账号和密码
return true;
}
return super.onAccessDenied(request, response);
}
}
验证码代码:
validatecode.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.Random"%>
<%@ page import="java.io.OutputStream"%>
<%@ page import="java.awt.Color"%>
<%@ page import="java.awt.Font"%>
<%@ page import="java.awt.Graphics"%>
<%@ page import="java.awt.image.BufferedImage"%>
<%@ page import="javax.imageio.ImageIO"%>
<%
int width = 60;
int height = 32;
//create the image
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// set the background color
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, width, height);
// draw the border
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
// create a random instance to generate the codes
Random rdm = new Random();
String hash1 = Integer.toHexString(rdm.nextInt());
// make some confusion
for (int i = 0; i < 50; i++) {
int x = rdm.nextInt(width);
int y = rdm.nextInt(height);
g.drawOval(x, y, 0, 0);
}
// generate a random code
String capstr = hash1.substring(0, 4);
//将生成的验证码存入session
session.setAttribute("validateCode", capstr);
g.setColor(new Color(0, 100, 0));
g.setFont(new Font("Candara", Font.BOLD, 24));
g.drawString(capstr, 8, 24);
g.dispose();
//输出图片
response.setContentType("image/jpeg");
out.clear();
out = pageContext.pushBody();
OutputStream strm = response.getOutputStream();
ImageIO.write(image, "jpeg", strm);
strm.close();
%>