本章基于上一章节:三、Springboot 整合Shiro---01认证
在上一章节上进行了一些小小改动:
实现了用户登陆记住我功能:
一、将BeetlAction.class中的登陆方法提取到,新创建类中:
package com.xslde.action;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
/**
* Created by xslde on 2018/7/21
*/
@Controller
public class LoginAction {
@GetMapping("/login")
public String login(){
return "login.html";
}
@PostMapping("/login")
public String login(String username,String password,boolean rememberMe,Model model){
//判断用户名和密码为空
if (StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
model.addAttribute("msg","用户名和密码不能为空!");
return "login.html";
}
//开始登录
//实际开发中,用户名和密码错误,不给出明确提示
try {
SecurityUtils.getSubject().login(new UsernamePasswordToken(username,password,rememberMe));
}catch (UnknownAccountException e){//未知用户异常
model.addAttribute("msg","用户名错误!");
return "login.html";
}catch (LockedAccountException e){//账户锁定
model.addAttribute("msg","账户被锁定!");
return "login.html";
}catch (CredentialsException e){//用户密码错误异常
model.addAttribute("msg","用户密码错误!");
return "login.html";
}catch (Exception e){
model.addAttribute("msg","其他异常!");
return "login.html";
}
return "redirect:/index";
}
}
二、对ShiroConf改动:
package com.xslde.configurer;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Author xslde
* @Description
* @Date 2018/7/20 16:25
*/
@Configuration
public class ShiroConf {
//注入shiro过滤器
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setSuccessUrl("/index");// 登录成功后要跳转的链接
Map<String, String> chains = new LinkedHashMap<>();
chains.put("/logout","logout");//登出
chains.put("/login", "anon");//anon表示可以匿名访问
//chains.put("/**", "authc");//表示需要认证,才能访问
chains.put("/**", "user");//表示需要认证或记a住我都能访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(chains);
return shiroFilterFactoryBean;
}
//安全管理器
@Bean
public WebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(shiroRealm());
securityManager.setCacheManager(cacheManager());
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
//会话管理器
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionIdUrlRewritingEnabled(false);
sessionManager.setGlobalSessionTimeout(1 * 60 * 60 * 1000);//session过期时间
sessionManager.setDeleteInvalidSessions(true);//是否删除过期session
sessionManager.setSessionIdCookie(rememberMeCookie());
return sessionManager;
}
//Realm,里面是自己实现的认证和授权业务逻辑
@Bean
public ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return shiroRealm;
}
//缓存管理
@Bean
public EhCacheManager cacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return cacheManager;
}
//密码管理
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5"); //散列算法使用md5
credentialsMatcher.setHashIterations(2); //散列次数,2表示md5加密两次
credentialsMatcher.setStoredCredentialsHexEncoded(true);//启用十六进制存储
return credentialsMatcher;
}
//cookie管理
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setHttpOnly(true);
cookie.setMaxAge(1 * 60 * 60);
return cookie;
}
//记住我
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//这个地方有点坑,不是所有的base64编码都可以用,长度过大过小都不行,没搞明白,官网给出的要么0x开头十六进制,要么base64
cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
return cookieRememberMeManager;
}
}
三、登陆页面改动:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="/login" method="post">
<div>
<span style="color: red;">${msg!}</span>
<br>
<div>
<label>用户名称:</label>
<input type="text" name="username" placeholder="请输入用户名称!">
</div>
<br>
<div>
<label>用户密码:</label>
<input type="password" name="password" placeholder="请输入用户密码!">
</div>
<div>
<input type="checkbox" checked="checked" name="rememberMe" />记住我
</div>
<br>
<input type="submit" value="登录" style="margin-left: 100px">
</div>
</form>
</body>
</html>
项目启动后效果如下:
登陆成功后打开浏览器调试,可看见rememberMe:
到此,记住我功能实现完成。
项目地址:springboot-example04