搭建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 filterChainDefinitionMap = new LinkedHashMap();
// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
// ;
//
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 filters = new HashMap();
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 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"%>
登录
登录
${msg}