首页
友链
关于
免责声明
Search
1
王者营地战绩数据王者荣耀查询网页源码
6,209 阅读
2
群晖Active Backup for Business套件备份Linux服务器教程
4,384 阅读
3
影视分享
4,313 阅读
4
(亲测)Jrebel激活破解方式2019-08-21
4,289 阅读
5
centos7 安装及卸载 jekenis
3,573 阅读
日常
文章
后端
前端
Linux
异常
Flutter
分享
群辉
登录
Search
标签搜索
docker
springboot
Spring Boot
java
linux
Shiro
Graphics2D
图片
游戏账号交易
Mybatis
Spring Cloud
centos
脚本
Web Station
群辉
王者营地
战绩查询
平台对接
Spring Cloud Alibaba
nacos
绿林寻猫
累计撰写
249
篇文章
累计收到
26
条评论
首页
栏目
日常
文章
后端
前端
Linux
异常
Flutter
分享
群辉
页面
友链
关于
免责声明
搜索到
3
篇与
Shiro
的结果
2021-12-08
Spring Boot 整合Shiro(一)登录认证和授权(附源码)
shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。主要功能三个核心组件:Subject, SecurityManager 和 Realms.Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。 Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。 SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。 Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。 从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。 Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。 1.项目版本Spring Boot 2.x shiro 1.3.21.1导入依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>2.类配置2.1 ShiroConfig相当于之前的xml配置,包括:过滤的文件和权限,密码加密的算法,其用注解等相关功能。import com.shiro.realm.CustomRealm; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import java.util.LinkedHashMap; import java.util.Map; /** * 过滤的文件和权限,密码加密的算法,其用注解等相关功能 */ @Configuration public class ShiroConfig { @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); // 身份认证失败,则跳转到登录页面的配置 shiroFilterFactoryBean.setLoginUrl("/login"); // 权限认证失败,则跳转到指定页面 shiroFilterFactoryBean.setUnauthorizedUrl("/notRole"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/front/**", "anon"); filterChainDefinitionMap.put("/api/**", "anon"); filterChainDefinitionMap.put("/admin/**", "authc"); filterChainDefinitionMap.put("/user/**", "authc"); //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); defaultSecurityManager.setRealm(customRealm()); return defaultSecurityManager; } @Bean public CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); return customRealm; } }2.1.1 shiroFilter方法shiro的过滤器,可以设置登录页面(setLoginUrl)、权限不足跳转页面(setUnauthorizedUrl)、具体某些页面的权限控制或者身份认证。注意:这里是需要设置SecurityManager(setSecurityManager)。默认的过滤器还有:anno、authc、authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user过滤器。具体的大家可以查看package org.apache.shiro.web.filter.mgt.DefaultFilter。这个类,常用的也就authc、anno。2.1.2 securityManager 方法public interface SecurityManager extends Authenticator, Authorizer, SessionManager { //登录方法 Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException; //注销方法 void logout(Subject subject); //创建subject Subject createSubject(SubjectContext context); }由于项目是一个web项目,所以我们使用的是DefaultWebSecurityManager ,然后设置自己的Realm。2.1.3 CustomRealm 方法将 customRealm的实例化交给spring去管理,当然这里也可以利用注解的方式去注入 2.2 CustomRealm自定义的CustomRealm继承AuthorizingRealm。并且重写父类中的doGetAuthorizationInfo(权限相关)、doGetAuthenticationInfo(身份认证)这两个方法。import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import java.util.HashSet; import java.util.Set; /** * */ public class CustomRealm extends AuthorizingRealm { /** * 权限相关 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //账户 String username = (String) SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //从数据库获取账户权限信息 Set<String> stringSet = new HashSet<>(); stringSet.add("user:show"); stringSet.add("user:admin"); info.setStringPermissions(stringSet); return info; } /** * 身份认证 * 这里可以注入userService,为了方便演示直接写死账户和密码 * 获取即将需要认证的信息 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("-------身份认证方法--------"); String userName = (String) authenticationToken.getPrincipal(); String userPwd = new String((char[]) authenticationToken.getCredentials()); System.out.println(userPwd); //根据用户名从数据库获取密码 String password = "123"; if (userName == null) { throw new AccountException("用户名不正确"); } else if (!userPwd.equals(password )) { throw new AccountException("密码不正确"); } return new SimpleAuthenticationInfo(userName, password,getName()); } } 自定义的Realm类继承AuthorizingRealm类,并且重载doGetAuthorizationInfo和doGetAuthenticationInfo两个方法。doGetAuthorizationInfo: 权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。doGetAuthenticationInfo:身份认证。即登录通过账号和密码验证登陆人的身份信息。 3.实战演练3.1 登陆认证创建LoginControllerimport org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.subject.Subject; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping public class LoginController { @RequestMapping(value = "/login", method = RequestMethod.GET) public String defaultLogin() { return "首页"; } @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(@RequestParam("username") String username, @RequestParam("password") String password) { // 从SecurityUtils里边创建一个 subject Subject subject = SecurityUtils.getSubject(); // 在认证提交前准备 token(令牌) UsernamePasswordToken token = new UsernamePasswordToken(username, password); // 执行认证登陆 try { subject.login(token); } catch (UnknownAccountException uae) { return "未知账户"; } catch (IncorrectCredentialsException ice) { return "密码不正确"; } catch (LockedAccountException lae) { return "账户已锁定"; } catch (ExcessiveAttemptsException eae) { return "用户名或密码错误次数过多"; } catch (AuthenticationException ae) { return "用户名或密码不正确!"; } if (subject.isAuthenticated()) { return "登录成功"; } else { token.clear(); return "登录失败"; } } }测试结果:3.2 权限测试在ShiroConfig添加如下代码,开启注解。@Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * * * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * * * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 * * @return */ @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); return authorizationAttributeSourceAdvisor; }创建UserControllerimport com.shiro.utils.BaseController; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/user") @RestController public class UserController extends BaseController { @RequiresPermissions("user:list") @RequestMapping("/show") public String showUser() { return "张三信息"; } }再创建 BaseController,UserController继承BaseController,用于捕获没有权限时的异常import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.UnauthorizedException; import org.springframework.web.bind.annotation.ExceptionHandler; import java.util.HashMap; import java.util.Map; public class BaseController { /** * 捕获没有权限时的异常 * @return */ @ExceptionHandler({ UnauthorizedException.class, AuthorizationException.class }) public Map<String, Object> authorizationException(){ Map<String, Object> map = new HashMap<String, Object>(); System.out.println("没有权限"); map.put("success", true); map.put("msg", "当前用户没有此权限"); return map; } } 运行测试,先执行 http://127.0.0.1:8080/login,再执行http://127.0.0.1:8080/user/show:方法上是 @RequiresPermissions("user:list"),之前在customRealm只添加了两个所以没有权限现在把方法上的改为@RequiresPermissions("user:show")测试现在就有权限访问数据啦4.项目源码项目地址 下篇介绍《Spring Boot 整合Shiro(二)加密登录与密码加盐处理》
2021年12月08日
425 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合Shiro(二)加密登录与密码加盐处理
该项目是根据上篇《Spring Boot 整合Shiro(一)登录认证和授权(附源码)》进行配置,若有不明白的请先查看上篇文章。1.加密工具用户注册时的密码用这个加密保存数据库 /** * 账户密码加密 * @param username * @param pwd * @return */ public static String MD5Pwd(String username, String pwd) { String hashAlgorithmName = "MD5";//加密方式 Object crdentials = pwd;//密码原值 ByteSource salt = ByteSource.Util.bytes(username);//以账号作为盐值 int hashIterations = 1024;//加密1024次 return new SimpleHash(hashAlgorithmName,crdentials,salt,hashIterations).toString(); }2.Shiro配置2.1修改ShiroConfig添加以下方法: /** * 加密配置 * @return */ @Bean(name = "credentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); // 散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashAlgorithmName("md5"); // 散列的次数,比如散列两次,相当于 md5(md5("")); hashedCredentialsMatcher.setHashIterations(1024); // storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码 hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true); return hashedCredentialsMatcher; }修改customRealm: @Bean public CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); // 告诉realm,使用credentialsMatcher加密算法类来验证密文 customRealm.setCredentialsMatcher(hashedCredentialsMatcher()); customRealm.setCachingEnabled(false); return customRealm; }2.2修改CustomRealm当中“password”参数值是用户注册时使用加密工具生产保存的密码,可在CustomRealm中配置UserService。/** * 身份认证 * 这里可以注入userService,为了方便演示直接写死账户和密码 * 获取即将需要认证的信息 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("-------身份认证方法--------"); String userName = (String) authenticationToken.getPrincipal(); // String userPwd = new String((char[]) authenticationToken.getCredentials()); //根据用户名从数据库获取密码 String password = "89267a06ce552c28e3edc11be28e4f80";// 使用账户和明文密码:123加密后 // if (userName == null) { // throw new AccountException("用户名不正确"); // } else if (!userPwd.equals(password )) { // throw new AccountException("密码不正确"); // } //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配 ByteSource salt = ByteSource.Util.bytes(userName); return new SimpleAuthenticationInfo(userName, password, salt, getName()); }3.实战演练使用账户:aa和密码:123 进行测试,可以看到提示登录成功。 之前的密码是根据账户和密码进行处理的,要注意的是注册的加密方式和设置的加密方式还有Realm中身份认证的方式都是要一模一样的 下篇介绍《Spring Boot 整合 Shiro(三)Kaptcha验证码》
2021年12月08日
363 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合 Shiro(三)Kaptcha验证码 附源码
前言本文是根据上篇《Spring Boot 整合Shiro(二)加密登录与密码加盐处理》进行修改,如有不明白的转上篇文章了解。1.导入依赖 <!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha --> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> 2.配置创建KaptchaConfig.javaimport com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.Properties; @Component public class KaptchaConfig { @Bean public DefaultKaptcha getDefaultKaptcha() { com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha(); Properties properties = new Properties(); // 图片边框 properties.setProperty("kaptcha.border", "yes"); // 边框颜色 properties.setProperty("kaptcha.border.color", "105,179,90"); // 字体颜色 properties.setProperty("kaptcha.textproducer.font.color", "red"); // 图片宽 properties.setProperty("kaptcha.image.width", "110"); // 图片高 properties.setProperty("kaptcha.image.height", "40"); // 字体大小 properties.setProperty("kaptcha.textproducer.font.size", "30"); // session key properties.setProperty("kaptcha.session.key", "code"); // 验证码长度 properties.setProperty("kaptcha.textproducer.char.length", "4"); // 字体 properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑"); //可以设置很多属性,具体看com.google.code.kaptcha.Constants // kaptcha.border 是否有边框 默认为true 我们可以自己设置yes,no // kaptcha.border.color 边框颜色 默认为Color.BLACK // kaptcha.border.thickness 边框粗细度 默认为1 // kaptcha.producer.impl 验证码生成器 默认为DefaultKaptcha // kaptcha.textproducer.impl 验证码文本生成器 默认为DefaultTextCreator // kaptcha.textproducer.char.string 验证码文本字符内容范围 默认为abcde2345678gfynmnpwx // kaptcha.textproducer.char.length 验证码文本字符长度 默认为5 // kaptcha.textproducer.font.names 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) // kaptcha.textproducer.font.size 验证码文本字符大小 默认为40 // kaptcha.textproducer.font.color 验证码文本字符颜色 默认为Color.BLACK // kaptcha.textproducer.char.space 验证码文本字符间距 默认为2 // kaptcha.noise.impl 验证码噪点生成对象 默认为DefaultNoise // kaptcha.noise.color 验证码噪点颜色 默认为Color.BLACK // kaptcha.obscurificator.impl 验证码样式引擎 默认为WaterRipple // kaptcha.word.impl 验证码文本字符渲染 默认为DefaultWordRenderer // kaptcha.background.impl 验证码背景生成器 默认为DefaultBackground // kaptcha.background.clear.from 验证码背景颜色渐进 默认为Color.LIGHT_GRAY // kaptcha.background.clear.to 验证码背景颜色渐进 默认为Color.WHITE // kaptcha.image.width 验证码图片宽度 默认为200 // kaptcha.image.height 验证码图片高度 默认为50 Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } } 3.验证码生成/验证import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.google.code.kaptcha.impl.DefaultKaptcha; @Controller @RequestMapping(value ="/kaptcha" ) public class KaptchaController { /** * 1、验证码工具 */ @Autowired DefaultKaptcha defaultKaptcha; /** * 2、生成验证码 * @param httpServletRequest * @param httpServletResponse * @throws Exception */ @RequestMapping("/defaultKaptcha") public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { byte[] captchaChallengeAsJpeg = null; ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream(); try { // 生产验证码字符串并保存到session中 String createText = defaultKaptcha.createText(); httpServletRequest.getSession().setAttribute("rightCode", createText); // 使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中 BufferedImage challenge = defaultKaptcha.createImage(createText); ImageIO.write(challenge, "jpg", jpegOutputStream); } catch (IllegalArgumentException e) { httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // 定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组 captchaChallengeAsJpeg = jpegOutputStream.toByteArray(); httpServletResponse.setHeader("Cache-Control", "no-store"); httpServletResponse.setHeader("Pragma", "no-cache"); httpServletResponse.setDateHeader("Expires", 0); httpServletResponse.setContentType("image/jpeg"); ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream(); responseOutputStream.write(captchaChallengeAsJpeg); responseOutputStream.flush(); responseOutputStream.close(); } /** * 3、校对验证码 * @param httpServletRequest * @param httpServletResponse * @return */ @RequestMapping("/imgvrifyControllerDefaultKaptcha") public ModelAndView imgvrifyControllerDefaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { ModelAndView andView = new ModelAndView(); String rightCode = (String) httpServletRequest.getSession().getAttribute("rightCode"); String tryCode = httpServletRequest.getParameter("tryCode"); System.out.println("rightCode:"+rightCode+" ———— tryCode:"+tryCode); if (!rightCode.equals(tryCode)) { andView.addObject("info", "错误的验证码"); andView.setViewName("/login"); } else { andView.addObject("info", "登录成功"); andView.setViewName("success"); } return andView; } } 4.修改ShiroConfig开放相应的验证码路径,避免拦截@Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); // 身份认证失败,则跳转到登录页面的配置 shiroFilterFactoryBean.setLoginUrl("/login"); // 权限认证失败,则跳转到指定页面 shiroFilterFactoryBean.setUnauthorizedUrl("/notRole"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/loginOut", "anon"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/front/**", "anon"); filterChainDefinitionMap.put("/api/**", "anon"); filterChainDefinitionMap.put("/kaptcha/**", "anon"); filterChainDefinitionMap.put("/success/**", "anon"); filterChainDefinitionMap.put("/admin/**", "authc"); filterChainDefinitionMap.put("/user/**", "authc"); //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; }5.修改LoginController@Controller @RequestMapping public class LoginController { private Logger logger = Logger.getLogger(this.getClass().getName()); /** * 界面 * @return */ @RequestMapping(value = "/login", method = RequestMethod.GET) public String defaultLogin() { return "login"; } /** * 退出 * @return */ @RequestMapping(value = "/loginOut", method = RequestMethod.GET) public String loginOut() { Subject subject = SecurityUtils.getSubject(); subject.logout(); return "login"; } /** * 登录提交 * @param username * @param tryCode * @param password * @param redirectAttributes * @return */ @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(@RequestParam("username") String username, @RequestParam("tryCode") String tryCode, @RequestParam("password") String password, RedirectAttributes redirectAttributes) { //判断验证码 if(StringUtils.isBlank(tryCode)){ logger.info("验证码为空了!"); redirectAttributes.addFlashAttribute("message", "验证码不能为空!"); return "redirect:login"; } Session session = SecurityUtils.getSubject().getSession(); String code = (String) session.getAttribute("rightCode"); System.out.println(code+"*************"+tryCode); if(!tryCode.equalsIgnoreCase(code)){ logger.info("验证码错误!"); redirectAttributes.addFlashAttribute("message", "验证码错误!"); return "redirect:login"; } // 从SecurityUtils里边创建一个 subject Subject subject = SecurityUtils.getSubject(); // 在认证提交前准备 token(令牌) UsernamePasswordToken token = new UsernamePasswordToken(username, password); String attributeValue = null; // 执行认证登陆 try { subject.login(token); } catch (UnknownAccountException uae) { attributeValue="未知账户!"; } catch (IncorrectCredentialsException ice) { attributeValue="密码不正确!"; } catch (LockedAccountException lae) { attributeValue= "账户已锁定"; } catch (ExcessiveAttemptsException eae) { attributeValue= "用户名或密码错误次数过多"; } catch (AuthenticationException ae) { attributeValue= "用户名或密码不正确!"; }finally { redirectAttributes.addFlashAttribute("message", attributeValue); if (subject.isAuthenticated()) { return "success"; } else { token.clear(); return "redirect:login"; } } } }6.界面6.1整合thymeleaf模板添加依赖;<!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>编辑application.ymlserver: port: 80 servlet: context-path: / #thymeleaf模板 spring: thymeleaf: cache: true prefix: classpath: /templates/ suffix: .html mode: HTML5 encoding: UTF-8 servlet: content-type: text/html 6.2创建login.html<!DOCTYPE html> <!-- thymeleaf 提示功能 --> <html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head lang="en"> <meta charset="UTF-8"></meta> <title>验证码</title> </head> <style type="text/css"> body { padding: 10px } </style> <body> <!-- 提示 --> <h3 th:text="${message}"></h3> <div> <!-- 后面添加参数起到清除缓存作用 --> <img alt="验证码" onclick="this.src='/kaptcha/defaultKaptcha?d='+new Date()*1" src="/kaptcha/defaultKaptcha" /> </div> <form action="/login" method="post"> 账户:<input type="text" name="username" /></br> 密码:<input type="text" name="password" /></br> 验证码:<input type="text" name="tryCode" /> <input type="submit" value="提交" ></input> </form> </body> </html> success.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>成功</title> </head> <body> <h1>登录成功</h1> <a href="/loginOut">退出</a> </body> </html> 7. 实战演练 8.项目源码《源码下载》下篇介绍Spring Boot 整合 Shiro(四)thymeleaf模板权限控制 附源码
2021年12月08日
388 阅读
0 评论
0 点赞