网上这种例子很多,我这里就不多说了,给大家一个大神些的链接,可以参考,我的文章是基于他的文章的学习曲线的描述。
第一章:http://412887952-qq-com.iteye.com/blog/2299732
第二章:http://412887952-qq-com.iteye.com/blog/2299777
需要注意的是所有的实体类最好都继承一下序列化类避免存储用户信息时出现异常~~。
这里头的shiro的密码加密方式为:md5(md5(输入密码+用户名+盐)) == password
通过这种方式完成校验,其中路径应当为http://127.0.0.1:8080/userAdd去掉userinfo路径
自动生成部分数据库实体代码:https://www.cnblogs.com/yingsong/p/5181430.html
第三章:http://412887952-qq-com.iteye.com/blog/2299780
其中注意如果想要设置ehcash进行用户登录锁定需要基于相关类重写处理请求的方法,而在进行校验时将会有shiro自动调用相关的类进行校验
第四章:http://412887952-qq-com.iteye.com/blog/2299784
第五章:http://blog.csdn.net/u014695188/article/details/52356158
以上部分能完成80%的shiro功能集成。但是除此以外你可能还需要添加验证码自定义权限功能等实现。那么请参考以下几位的博客
附注:
http://412887952-qq-com.iteye.com/blog/2391142
http://blog.csdn.net/poorcoder_/article/details/71374002
http://www.jianshu.com/p/7bf5dc61ca06
http://www.cnblogs.com/yjmyzz/p/how-to-inject-multi-redis-instance-in-spring-boot.html
http://ask.csdn.net/questions/652023
http://www.cnblogs.com/digdeep/p/4612053.html
shiro存储session的解释
http://www.xuebuyuan.com/2116235.html
shiro拦截器:
https://www.cnblogs.com/koal/p/5152671.html
http://jinnianshilongnian.iteye.com/blog/2025656
需要了解的是:
anon:所有url都都可以匿名访问;
authc: 需要认证才能进行访问;
user:配置记住我或认证通过可以访问;
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port | org.apache.shiro.web.filter.authz.PortFilter |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl | org.apache.shiro.web.filter.authz.SslFilter |
user | org.apache.shiro.web.filter.authc.UserFilter |
唯一登录用户
实现方式为在处理中将session删除,添加过滤器的方式最终还是是失败了,此处欢迎大神指导下实现方式。
记住我
当浏览器不清缓存的时候不去向后台获取session信息,目前通过每次登陆时将原有的登陆信息清除的方式进行重新登录。建议不使用此功能,可能导致过多的第二次登录的session信息存储。
测试ajax登录请求以及相关的ajax请求的拦截操作
如果是ajax则只能通过返回字符串的形式进行客户端的页面跳转不使用服务器重定向,但是通过过滤器应该可以实现相关业务处理
验证码加入
如何清除浏览器缓存的网页信息
查看下shiro的在user下前后的session的不同之处,查下为啥两次的session信息不一样导致之前删掉了自己的问题
此问题并非浏览器的原因,是由于图片加载时先将response返回导致系统内部可能出现异常所以session下一次登录时会重新生成一个session。当先将信息加载完毕最后进行返回就不会出现异常。因此之前引用的项目实际上是有问题。请注意此处获取验证码的代码使用以下方式:
/**
* 获取验证码(Gif版本)
* @param response
*/
@RequestMapping(value="getGifCode",method= RequestMethod.GET)
@ResponseBody
public void getGifCode(HttpServletResponse response, HttpServletRequest request ,Map<String, Object> map){
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/gif");
/**
* gif格式动画验证码
* 宽,高,位数。
*/
GifCaptcha captcha = new GifCaptcha(146,33,4);
//输出
char [] c = captcha.alphas();
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession(true);
System.out.println(session.getId());
//HttpSession httpSession = request.getSession(true);
String code = (String)session.getAttribute("_code");
System.out.println(code);
//存入Session
session.setAttribute("_code",captcha.text().toLowerCase());
code = (String)session.getAttribute("_code");
map.put("_code",code);
captcha.out(c,response.getOutputStream());
System.out.println(code);
} catch (Exception e) {
// LoggerUtils.fmtError(getClass(),e, "获取验证码异常:%s",e.getMessage());
System.out.println("获取验证码异常:" + e.getMessage());
}
}
Gif验证码实现代码请参考以下实现:
package demo.VerificationCode;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
/**
* <p>Gif验证码类</p>
*
* @author: wuhongjun
* @version:1.0
*/
public class GifCaptcha extends Captcha
{
public GifCaptcha()
{
}
public GifCaptcha(int width,int height){
this.width = width;
this.height = height;
}
public GifCaptcha(int width,int height,int len){
this(width,height);
this.len = len;
}
public GifCaptcha(int width,int height,int len,Font font)
{
this(width,height,len);
this.font = font;
}
@Override
public void out(OutputStream os)
{
try
{
GifEncoder gifEncoder = new GifEncoder(); // gif编码类,这个利用了洋人写的编码类,所有类都在附件中
//生成字符
gifEncoder.start(os);
gifEncoder.setQuality(180);
gifEncoder.setDelay(100);
gifEncoder.setRepeat(0);
BufferedImage frame;
char[] rands =alphas();
Color fontcolor[]=new Color[len];
for(int i=0;i<len;i++)
{
fontcolor[i]=new Color(20 + num(110), 20 + num(110), 20 + num(110));
}
for(int i=0;i<len;i++)
{
frame=graphicsImage(fontcolor, rands, i);
gifEncoder.addFrame(frame);
frame.flush();
}
gifEncoder.finish();
}finally
{
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public char[] alphas(){
return super.alphas();
}
public void out(char[] rands,OutputStream os)
{
try
{
GifEncoder gifEncoder = new GifEncoder(); // gif编码类,这个利用了洋人写的编码类,所有类都在附件中
//生成字符
gifEncoder.start(os);
gifEncoder.setQuality(180);
gifEncoder.setDelay(100);
gifEncoder.setRepeat(0);
BufferedImage frame;
Color fontcolor[]=new Color[len];
for(int i=0;i<len;i++)
{
fontcolor[i]=new Color(20 + num(110), 20 + num(110), 20 + num(110));
}
for(int i=0;i<len;i++)
{
frame=graphicsImage(fontcolor, rands, i);
gifEncoder.addFrame(frame);
frame.flush();
}
gifEncoder.finish();
}finally
{
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 画随机码图
* @param fontcolor 随机字体颜色
* @param strs 字符数组
* @param flag 透明度使用
* @return BufferedImage
*/
private BufferedImage graphicsImage(Color[] fontcolor,char[] strs,int flag)
{
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
//或得图形上下文
//Graphics2D g2d=image.createGraphics();
Graphics2D g2d = (Graphics2D)image.getGraphics();
//利用指定颜色填充背景
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
AlphaComposite ac3;
int h = height - ((height - font.getSize()) >>1) ;
int w = width/len;
g2d.setFont(font);
for(int i=0;i<len;i++)
{
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3);
g2d.setColor(fontcolor[i]);
g2d.drawOval(num(width), num(height), 5+num(10), 5+num(10));
g2d.drawString(strs[i]+"", (width-(len-i)*w)+(w-font.getSize())+1, h-4);
}
g2d.dispose();
return image;
}
/**
* 获取透明度,从0到1,自动计算步长
* @return float 透明度
*/
private float getAlpha(int i,int j)
{
int num = i+j;
float r = (float)1/len,s = (len+1) * r;
return num > len ? (num *r - s) : num * r;
}
}
package demo.VerificationCode;
import java.awt.*;
import java.io.OutputStream;
/**
* <p>
* 验证码抽象类,暂时不支持中文
* </p>
*
* @author: wuhongjun
* @version:1.0
*/
public abstract class Captcha extends Randoms {
protected Font font = new Font("Verdana", Font.ITALIC | Font.BOLD, 28); // 字体
protected int len = 5; // 验证码随机字符长度
protected int width = 150; // 验证码显示跨度
protected int height = 40; // 验证码显示高度
private String chars = null; // 随机字符串
/**
* 生成随机字符数组
*
* @return 字符数组
*/
protected char[] alphas() {
char[] cs = new char[len];
for (int i = 0; i < len; i++) {
cs[i] = alpha();
}
chars = new String(cs);
return cs;
}
public Font getFont() {
return font;
}
public void setFont(Font font) {
this.font = font;
}
public int getLen() {
return len;
}
public void setLen(int len) {
this.len = len;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
/**
* 给定范围获得随机颜色
*
* @return Color 随机颜色
*/
protected Color color(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + num(bc - fc);
int g = fc + num(bc - fc);
int b = fc + num(bc - fc);
return new Color(r, g, b);
}
/**
* 验证码输出,抽象方法,由子类实现
*
* @param os
* 输出流
*/
public abstract void out(OutputStream os);
/**
* 获取随机字符串
*
* @return string
*/
public String text() {
return chars;
}
}
package demo.VerificationCode;
import java.util.Random;
/**
* <p>随机工具类</p>
*
* @author: wuhongjun
* @version:1.0
*/
public class Randoms
{
private static final Random RANDOM = new Random();
//定义验证码字符.去除了O和I等容易混淆的字母
public static final char ALPHA[]={'A','B','C','D','E','F','G','H','G','K','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'
,'a','b','c','d','e','f','g','h','i','j','k','m','n','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7','8','9'};
/**
* 产生两个数之间的随机数
* @param min 小数
* @param max 比min大的数
* @return int 随机数字
*/
public static int num(int min, int max)
{
return min + RANDOM.nextInt(max - min);
}
/**
* 产生0--num的随机数,不包括num
* @param num 数字
* @return int 随机数字
*/
public static int num(int num)
{
return RANDOM.nextInt(num);
}
public static char alpha()
{
return ALPHA[num(0, ALPHA.length)];
}
}
以上能满足基本的java代码实现。
后记添加数据库事务
事务
使用事务的相关属性:http://www.cnblogs.com/xusir/p/3650522.html
事务方法的使用:http://blog.csdn.net/wohaqiyi/article/details/72895983
2018年1月29日追加
在使用时请注意如果你使用了shiro那么他会和
spring-boot-devtools
产生冲突,冲突原因可能是由于热部署的加载方式导致的,因此在项目实施过程中不能使用此jar包