登录后
登录缓存
退出浏览器后再重新进入 http://localhost:8080/south/index.html不需要登录 便可进入index.html页面
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<packaging>war</packaging>
<modelVersion>4.0.0</modelVersion>
<groupId>com.nany</groupId>
<artifactId>south</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>south</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<!-- ******************************* 常用依赖库 ********************************** -->
<commons.io.version>2.4</commons.io.version>
<commons.fileupload.version>1.3.1</commons.fileupload.version>
<commons.collections.version>3.2</commons.collections.version>
<commons.beanutils.version>1.9.2</commons.beanutils.version>
<commons.codec.version>1.10</commons.codec.version>
<commons.lang3.version>3.6</commons.lang3.version>
<guava.version>23.0</guava.version>
</properties>
<!-- 针对开发IO流功能的工具类库 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mybatis依赖-->
<!--mybatis通用Mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>2.1.2</version>
</dependency>
<!--mybatis分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.7</version>
</dependency>
<!--logback 日志-->
<!--<dependency>-->
<!--<groupId>org.codehaus.janino</groupId>-->
<!--<artifactId>janino</artifactId>-->
<!--<version>2.6.1</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>commons-compiler</artifactId>
<version>3.0.9</version>
</dependency>
<!-- druid阿里巴巴数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!--MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.1.0.jre8</version>
</dependency>
<!-- redis缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
<exclusions>
<exclusion>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 常用的集合操作,丰富的工具类 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons.collections.version}</version>
</dependency>
<!-- 操作javabean的工具包 -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons.beanutils.version}</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 包含一些通用的编码解码算法. 如:MD5、SHA1、Base64等 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<!-- 包含丰富的工具类如 StringUtils -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<!--
Guava工程包含了若干被Google的Java项目广泛依赖的核心库. 集合[collections] 、缓存[caching] 、原生类型支持[primitives support] 、
并发库[concurrency libraries] 、通用注解[common annotations] 、字符串处理[string processing] 、I/O 等等。
-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>clojars</id>
<url>http://clojars.org/repo/</url>
</repository>
</repositories>
<build>
<finalName>south</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
</project>
package com.nanty.core.system.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.nanty.core.base.BaseDTO;
import com.nanty.core.util.Dates;
import javax.persistence.*;
import java.util.Date;
/**
* 系统用户
*
* @name User
* @version 1.0
* @author ling 2020-05-06
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@Table(name = "SYS_USER")
public class User {
private static final long serialVersionUID = -7395431342743009038L;
/**
* 用户ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@OrderBy("DESC")
private Long userId;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 昵称
*/
private String nickname;
/**
* 生日
*/
@JsonFormat(pattern = Dates.Pattern.DATE)
private Date birthday;
/**
* 性别:1-男/0-女
*/
private Integer sex;
/**
* 是否启用:1/0
*/
private Integer enabled;
private String salt;//加密密码的盐
private byte state;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Integer getEnabled() {
return enabled;
}
public void setEnabled(Integer enabled) {
this.enabled = enabled;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public byte getState() {
return state;
}
public void setState(byte state) {
this.state = state;
}
/**
* 密码盐.
* @return
*/
public String getCredentialsSalt(){
return this.username+this.salt;
}
@Override
public String toString() {
return "UserInfo [userId=" + userId + ", username=" + username + ", nickname=" + nickname + ", password=" + password
+ ", salt=" + salt + ", state=" + state + "]";
}
}
Service
package com.nanty.core.system.service;
import com.nanty.core.base.Service;
import com.nanty.core.system.entity.User;
/**
* 用户Service接口
*
* @version 1.0
* @author ling 2020-04-28
*/
public interface UserService {
User selectName(String username);
}
ServiceImpl
package com.nanty.core.system.service.impl;
import com.nanty.core.system.mapper.db1.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.nanty.core.base.BaseService;
import com.nanty.core.system.entity.User;
import com.nanty.core.system.service.UserService;
/**
* 用户Service实现类
*
* @version 1.0
* @author ling 2020-04-28
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User selectName(String username) {
return userMapper.selectName(username);
}
}
Mapper
package com.nanty.core.system.mapper.db1;
import com.nanty.core.base.Mapper;
import com.nanty.core.system.entity.User;
import org.apache.ibatis.annotations.Param;
/**
*
* @name UserMapper
* @version 1.0
* @author ling 2020-05-06
*/
@org.apache.ibatis.annotations.Mapper
public interface UserMapper{
User selectName(@Param("username")String username);
}
Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nanty.core.system.mapper.db1.UserMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.nanty.core.system.entity.User">
<id column="USER_ID" property="userId" />
<result column="USERNAME" property="username" />
<result column="PASSWORD" property="password" />
<result column="NICKNAME" property="nickname" />
<result column="BIRTHDAY" property="birthday" />
<result column="SEX" property="sex" />
<result column="ENABLED" property="enabled" />
<result column="salt" property="salt" />
<result column="state" property="state" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
USER_ID AS userId, USERNAME AS username, PASSWORD AS password, NICKNAME AS nickname, BIRTHDAY AS birthday, SEX AS sex, ENABLED AS enabled,salt AS salt,state AS state
</sql>
<select id="selectName" resultMap="BaseResultMap">
select * from SYS_USER
where USERNAME=#{username}
</select>
</mapper>
项目目录
MyShiroRealm 用户身份验证,判断登录的账号密码
package com.nanty.core.shiro;
import com.nanty.core.system.entity.User;
import com.nanty.core.system.service.UserService;
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 org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("开始身份验证");
String username = (String) token.getPrincipal(); //获取用户名,默认和login.html中的username对应。
System.out.println("---0-------------"+username);
User userInfo = userService.selectName(username);
if (userInfo == null) {
//没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
throw new UnknownAccountException("用户名不存在!");
}
if ("1".equals(userInfo.getState())) {
throw new LockedAccountException("账号已被锁定,请联系管理员!");
}
//验证通过返回一个封装了用户信息的AuthenticationInfo实例即可。
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用户信息
userInfo.getPassword(), //密码
getName() //realm name
);
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userInfo.getCredentialsSalt())); //设置盐
return authenticationInfo;
}
//当访问到页面的时候,链接配置了相应的权限或者shiro标签才会执行此方法否则不会执行
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("开始权限配置");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User userInfo = (User) principalCollection.getPrimaryPrincipal();
// for (SysRole role: userInfo.getRoleList()) {
// authorizationInfo.addRole(role.getRole());
// for (SysPermission p: role.getPermissions()) {
// authorizationInfo.addStringPermission(p.getPermission());
// }
// }
return authorizationInfo;
}
}
ShiroConfiguration.java
package com.nanty.core.shiro;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfiguration {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/logout", "logout"); //退出登录
filterChainDefinitionMap.put("/index", "user");
filterChainDefinitionMap.put("/", "user");
filterChainDefinitionMap.put("/favicon.ico", "anon");
// filterChainDefinitionMap.put("/kaptcha.jpg", "anon");//图片验证码(kaptcha框架)
filterChainDefinitionMap.put("/Captcha.jpg", "anon");//图片验证码(kaptcha框架)
filterChainDefinitionMap.put("/register", "anon");
filterChainDefinitionMap.put("/logina", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**","anon");
// filterChainDefinitionMap.put("/login.html", "kaptchaFilter");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setLoginUrl("/login.html");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
securityManager.setCacheManager(ehCacheManager());
securityManager.setRememberMeManager(cookieRememberMeManager());
return securityManager;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
@Bean
public EhCacheManager ehCacheManager() {
System.out.println("ShiroConfiguration.getEhCacheManager()");
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
return ehCacheManager;
}
//cookie对象;
@Bean
public SimpleCookie rememberMeCookie() {
System.out.println("ShiroConfiguration.rememberMeCookie()");
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
//cookie管理对象;
@Bean
public CookieRememberMeManager cookieRememberMeManager() {
System.out.println("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager manager = new CookieRememberMeManager();
manager.setCookie(rememberMeCookie());
return manager;
}
}
ehcache-shiro.xml 账号登录缓存
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<!-- 登录记录缓存锁定10分钟 -->
<cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
</ehcache>
验证码
CaptchaUtil 生成验证码工具类
package com.nanty.core.shiro.kaptcha;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* 验证码工具类
*/
public class CaptchaUtil {
// 随机产生的字符串
private static final String RANDOM_STRS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String FONT_NAME = "Fixedsys";
private static final int FONT_SIZE = 18;
private Random random = new Random();
private int width = 80;// 图片宽
private int height = 25;// 图片高
private int lineNum = 50;// 干扰线数量
private int strNum = 4;// 随机产生字符数量
/**
* 生成随机图片
*/
public BufferedImage genRandomCodeImage(StringBuffer randomCode) {
// BufferedImage类是具有缓冲区的Image类
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_BGR);
// 获取Graphics对象,便于对图像进行各种绘制操作
Graphics g = image.getGraphics();
// 设置背景色
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
// 设置干扰线的颜色
g.setColor(getRandColor(110, 120));
// 绘制干扰线
for (int i = 0; i <= lineNum; i++) {
drowLine(g);
}
// 绘制随机字符
g.setFont(new Font(FONT_NAME, Font.ROMAN_BASELINE, FONT_SIZE));
for (int i = 1; i <= strNum; i++) {
randomCode.append(drowString(g, i));
}
g.dispose();
return image;
}
/**
* 给定范围获得随机颜色
*/
private Color getRandColor(int fc, int bc) {
if (fc > 255){
fc = 255;
}
if (bc > 255){
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
/**
* 绘制字符串
*/
private String drowString(Graphics g, int i) {
g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
.nextInt(121)));
String rand = String.valueOf(getRandomString(random.nextInt(RANDOM_STRS
.length())));
g.translate(random.nextInt(3), random.nextInt(3));
g.drawString(rand, 13 * i, 16);
return rand;
}
/**
* 绘制干扰线
*/
private void drowLine(Graphics g) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int x0 = random.nextInt(16);
int y0 = random.nextInt(16);
g.drawLine(x, y, x + x0, y + y0);
}
/**
* 获取随机的字符
*/
private String getRandomString(int num) {
return String.valueOf(RANDOM_STRS.charAt(num));
}
public static void main(String[] args) {
CaptchaUtil tool = new CaptchaUtil();
StringBuffer code = new StringBuffer();
BufferedImage image = tool.genRandomCodeImage(code);
System.out.println("random code = " + code);
try {
// 将内存中的图片通过流动形式输出到客户端
ImageIO.write(image, "JPEG", new FileOutputStream(new File(
"/Users/wangsaichao/Desktop/random-code.jpg")));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.nanty.core.shiro.kaptcha;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* @author: wangsaichao
* @date: 2018/5/26
* @description:
*/
@Controller
public class CaptchaController {
public static final String KEY_CAPTCHA = "KEY_CAPTCHA";
@RequestMapping("/Captcha.jpg")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
// 设置相应类型,告诉浏览器输出的内容为图片
response.setContentType("image/jpeg");
// 不缓存此内容
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
try {
HttpSession session = request.getSession();
CaptchaUtil tool = new CaptchaUtil();
StringBuffer code = new StringBuffer();
BufferedImage image = tool.genRandomCodeImage(code);
session.removeAttribute(KEY_CAPTCHA);
System.out.println("-------------------------");
System.out.println(code);
session.setAttribute(KEY_CAPTCHA, code.toString());
// 将内存中的图片通过流动形式输出到客户端
ImageIO.write(image, "JPEG", response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.nanty.core.system.controller;
import com.nanty.core.base.Result;
import com.nanty.core.exception.BaseEnums;
import com.nanty.core.shiro.kaptcha.CaptchaController;
import com.nanty.core.shiro.kaptcha.IncorrectCaptchaException;
import com.nanty.core.system.entity.User;
import com.nanty.core.system.service.UserService;
import com.nanty.core.util.Results;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.apache.ibatis.annotations.Param;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 用户Controller
*
* @version 1.0
* @author ling 2020-05-10
*/
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping(value = "/logina")
public Result logina(String username,String password,String captcha) throws Exception {
//session中的验证码
String msg = "";
System.out.println("11111111111111");
String sessionCaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(CaptchaController.KEY_CAPTCHA);
System.out.println(sessionCaptcha);
if (null == captcha || !captcha.equalsIgnoreCase(sessionCaptcha)) {
System.out.println("验证码不正确");
msg = "验证码不正确";
}else {
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
System.out.println(token);
try {
subject.login(token);
} catch (UnknownAccountException uae) {//UsernamePasswordToken
msg = "用户名不存在";
} catch (IncorrectCredentialsException ice) {
msg = "密码不正确";
} catch (LockedAccountException lae) {
msg = "账户已锁定";
} catch (ExcessiveAttemptsException eae) {
msg = "用户名或密码错误次数过多";
} catch (AuthenticationException ae) {
msg = "用户名或密码不正确";
}
if (subject.isAuthenticated()) {
msg = "登录成功";
} else {
token.clear();
msg = "登录失败";
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
错误信息:<h4 style="color: red;" ></h4>
<form >
<p>账号:<input type="text" name="username" id="username" value="admin"/></p>
<p>密码:<input type="password" name="password" id="password" value="123456"/></p>
<div><label> 验证码 : <input type="text" name="captcha" id="captcha" placeholder="验证码"/> </label></div>
<div><img src="/south/Captcha.jpg" class="pull-right" id="captcha_img" style="cursor: pointer;" onclick="this.src=this.src+'?d='+Math.random();" title="点击刷新" alt="captcha"></div>
<P><input type="checkbox" name="rememberMe" />记住我</P>
<p><input type="button" onclick="lonin()" value="登录"/></p>
</form>
<script type="text/javascript" src="/south/js/jquery.min.js"></script>
<script>
function lonin() {
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
var captcha = document.getElementById('captcha').value;
alert(username)
$.ajax({
url:"/south/logina",
data:{username:username,password:password,captcha:captcha},
dataType:'json',
type:'post',
success:function (data) {
alert(data.msg)
window.location.href = "/south/index.html";
}
})
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
....index
<li class="layui-nav-item"><a href="/south/logout"><i class="fa fa-sign-out" aria-hidden="true"></i> 注销</a></li>
</body>
</html>
密码加密方式
String name="123";
String salt="e10adc3949ba59abbe56e057f20f883e";
String passworaaa= new Md5Hash("123456",name+salt,2).toHex();