springboot+shiro

搭建springboot  http://blog.csdn.net/qq_16414483/article/details/79371192

先在 user类 追加段 盐 代码

	private String salt;
	/**
	 * 密码盐.
	 * @return
	 */
	public String getCredentialsSalt() {
		return this.userName + this.salt;
	}
	public String getSalt() {
		return salt;
	}
	public void setSalt(String salt) {
		this.salt = salt;
	}

建好包

第一个类 加密算法

package com.java.Olym.shiro;

import java.security.Key;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.java.Olym.explore.entity.User;

public final class EndecryptUtils { 
	private static final Logger log = LoggerFactory.getLogger(EndecryptUtils.class);
    /** 
     * base64进制加密 
     * 
     * @param password 
     * @return 
     */ 
    public static String encrytBase64(String password) { 
    	if(!StringUtils.hasText(password)){
    		log.info("$--password 不能为空!");
    	}
        byte[] bytes = password.getBytes(); 
        return Base64.encodeToString(bytes); 
    } 
    /** 
     * base64进制解密 
     * @param cipherText 
     * @return 
     */ 
    public static String decryptBase64(String cipherText) { 
    	if(!StringUtils.hasText(cipherText)){
        log.info("$--cipherText 消息摘要不能为空!");
    	}
        return Base64.decodeToString(cipherText); 
    } 
    /** 
     * 16进制加密 
     * 
     * @param password 
     * @return 
     */ 
    public static String encrytHex(String password) { 
    	if(!StringUtils.hasText(password)){
    	log.info("$--password 不能为空!");
    	}
        byte[] bytes = password.getBytes(); 
        return Hex.encodeToString(bytes); 
    } 
    /** 
     * 16进制解密 
     * @param cipherText 
     * @return 
     */ 
    public static String decryptHex(String cipherText) { 
    	if(!StringUtils.hasText(cipherText)){
    	log.info("$--cipherText 消息摘要不能为空!");
    	}
        return new String(Hex.decode(cipherText)); 
    } 
    public static String generateKey() 
    { 
        AesCipherService aesCipherService=new AesCipherService(); 
        Key key=aesCipherService.generateNewKey(); 
        return Base64.encodeToString(key.getEncoded()); 
    } 
    /** 
     * 对密码进行md5加密,并返回密文和salt,包含在User对象中 
     * @param username 用户名 
     * @param password 密码 
     * @return 密文和salt 
     */ 
    public static User md5Password(String username,String password){ 
    	if(!StringUtils.hasText(username)){
    		log.info("$--username 不能为空!");
    	}
    	if(!StringUtils.hasText(password)){
    		log.info("$--password 不能为空!");
    	}
        SecureRandomNumberGenerator secureRandomNumberGenerator=new SecureRandomNumberGenerator(); 
        String salt= "78240633979e0d912d1e0a9d52f8f352";//secureRandomNumberGenerator.nextBytes().toHex();
        //String salt  = username+username;
        log.info("$--这是salt!--"+salt);
        //组合username,两次迭代,对密码进行加密 
        String password_cipherText= new Md5Hash(password,username+salt,2).toHex(); 
        User user=new User(); 
        user.setUserPassword(password_cipherText); 
        user.setSalt(salt); 
        user.setUserName(username); 
        return user; 
    } 
    public static void main(String[] args) { 	
    	User u  = md5Password("admin", "123456");
    	log.info(String.format("$-loginName=%s;password=%s;salt=%s", u.getUserName(),u.getUserPassword(),u.getSalt()));
    } 
}

第二个类 验证码生成

package com.java.Olym.shiro;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet(urlPatterns = "/validatecodeServlet")
public class ValidatecodeServlet extends HttpServlet {

	private static final long serialVersionUID = -3558073720446002853L;
	private final Logger log = LoggerFactory.getLogger(this.getClass());

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		log.info("$-生成验证码1>>>>>>>>>>doGet()<<<<<<<<<<<");
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		log.info("$-生成验证码2>>>>>>>>>>doPost()<<<<<<<<<<<");
		int width = 72;
		int height = 34;
		// 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 hash_ = Integer.toHexString(rdm.nextInt());
		log.info("$-验证码hash1:" + hash_);
		// 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 = hash_.substring(0, 4);
		HttpSession session = req.getSession(true);
		// 将生成的验证码存入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();
		// 输出图片
		resp.setContentType("image/jpeg");
		OutputStream strm = resp.getOutputStream();
		ImageIO.write(image, "jpeg", strm);
		strm.close();

	}
}

第三个 shiro配置类

package com.java.Olym.shiro;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * Shiro 配置
 */
@Configuration
public class ShiroConfiguration {
	private final Logger log = LoggerFactory.getLogger(this.getClass());

	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		log.info("$--ShiroConfiguration.shirFilter()");
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		//拦截器.
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
		filterChainDefinitionMap.put("/logout", "logout");
		// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->;
		// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
		filterChainDefinitionMap.put("/validatecodeServlet", "anon");//验证码可以匿名访问
		filterChainDefinitionMap.put("/toPasswordReset", "anon");//重置密码可以匿名访问
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/**", "authc");//authc
		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 登录成功后要跳转的链接
		shiroFilterFactoryBean.setSuccessUrl("/index");
		// 未授权界面;
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		//自定义表达验证,校验验证码
		Map<String,Filter> filters = new HashMap<String, Filter>();
		filters.put("authc", new MyFormAuthenticationFilter());
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		shiroFilterFactoryBean.setFilters(filters);
		return shiroFilterFactoryBean;
	}

	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		//设置realm.
	    securityManager.setRealm(myShiroRealm());
		return securityManager;
	}
	
	/**
     * 身份认证realm;
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm(){
       MyShiroRealm myShiroRealm = new MyShiroRealm();
       myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
       return myShiroRealm;
    }
    
    /**
	 * 凭证匹配器
	 * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
	 *  所以我们需要修改下doGetAuthenticationInfo中的代码;
	 * )
	 * @return
	 */
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher(){
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		
		hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
		hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列2次,相当于 md5(md5(""));
		
		return hashedCredentialsMatcher;
	}
	
    @Bean  
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {  
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();  
        advisor.setSecurityManager(securityManager());  
        return advisor;  
    }  
}

第四个类 前端传来 验证码验证

package com.java.Olym.shiro;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
	
	    @Override    
	    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {    
	        // 在这里进行验证码的校验    
	        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.trim())) {    
	            // 如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中    
	            httpServletRequest.setAttribute("shiroLoginFailure", "kaptchaValidateFailed");//自定义登录异常    
	            // 拒绝访问,不再校验账号和密码    
	            return true;    
	        }    
	        return super.onAccessDenied(request, response);    
	    }    
}

第五个类 realm  最重要的类,权限和登录都在这个类进行

 

package com.java.Olym.shiro;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class MyShiroRealm extends AuthorizingRealm {
	private final Logger log = LoggerFactory.getLogger(this.getClass());
	@Resource
	private UserService userService;
	
	/**
	 * 验证用户身份
	 * 
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException  {
		log.info("$--验证用户身份:MyShiroRealm.doGetAuthenticationInfo()");
		 //获取用户的输入的账号.
		String loginName = ((String)token.getPrincipal()).trim();
		char[] pwd = (char[]) token.getCredentials();
		/*UsernamePasswordToken loginToken = (UsernamePasswordToken) token;
		String username = loginToken.getUsername();*/
		log.info(String.format("$--loginName=%s;pwd=%s",loginName,String.valueOf(pwd)));
		User userInfo = userService.getUser(loginName);
		if(userInfo!=null )		
		{ 
				SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
						userInfo.getUserName(), //用户名(数据库查询出来)
						userInfo.getPassword(), //密码(数据库查询出来)
						ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt  ByteSource.Util.bytes(userInfo.getCredentialsSalt()
						getName() //realm name
						); 	
				Subject currentUser = SecurityUtils.getSubject(); 
		        Session session = currentUser.getSession();
				session.setAttribute("userInfo",userInfo);
				return authenticationInfo;
			}
		return null;
	}
		
	/**
	 * 权限信息 
	 * 此方法调用  hasRole,hasPermission的时候才会进行回调.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;

	}
			

}
usercontroller代码
package com.java.Olym.explore.controller;

import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.java.Olym.explore.service.UserService;

@Controller
public class UserController {
	
	private final Logger log = Logger.getLogger(this.getClass());
	@Resource
	private UserService userService;
	
	@RequestMapping(value="/login",method=RequestMethod.GET)
	public String all(){
		return "login";
	}
	@RequestMapping(value="/login",method=RequestMethod.POST)
	public String login(String username,String password,HttpServletRequest req,Map<String, Object> map){
		log.info("$--UserController.login().post");
		String msg = "";
		String exception = (String)req.getAttribute("shiroLoginFailure");
		
		if(exception!=null){
			if(UnknownAccountException.class.getName().equals(exception)){
				log.info("账号不存在");
				msg = "账号不存在";
			}else if(IncorrectCredentialsException.class.getName().equals(exception)){
				log.info("密码不正确");
				msg = "密码不正确";
			}else if("kaptchaValidateFailed".equals(exception)){
				log.info("验证码错误");
				msg = "验证码错误";
			}else{
				msg = "错误"+exception;
				log.info("未知错误");
			}
			map.put("msg", msg);
			return "login";
		}
		return "login";
	}
	@RequestMapping({"/","/index"})
	public String in(){
		return "index";
	}
}

登录html页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ include file="./res.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录</title>
<script type="text/javascript">
function random(tmp){  
     tmp.src="<%=url%>/validatecodeServlet?rnd=" + Math.random();
	};
</script>
</head>
<body>
	<div id="login">
		<h2>登录</h2>
		<form action="<%=ctx%>/login" method="post">
			<span>用户名<input type="text" name="username"/></span><p>
			<span>密码<input type="password" name="password"/></span><p>
			<input name="randomcode" type="text" placehoder="请输入验证码">
			<img src="<%=url%>/validatecodeServlet" height="20px" width="60px" οnclick="random(this)"><p>
            <div class="loginMain_btn" type="submit" id="login">登录</div><p>
            </form>
             <center><h4 th:text="${requestScope.msg}" style="color:red;font-size:16px;padding-top:6px">${msg}</h4></center>
	</div>
</body>
</html>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值