一.导入依赖包
<!--spring boot 默认lettuce连接redis的技术-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--邮件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--jdbc依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--前端模板引擎依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--springmvc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!--热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--mysql数据库依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--简化实体类依赖(set/get)-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--单元测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!-- SpringBoot - MyBatis 逆向工程 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--EXCEL-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>net.oschina.likaixuan</groupId>
<artifactId>excelutil</artifactId>
<version>2.0.2</version>
</dependency>
<!--对象池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
<!-- fastjson阿里巴巴jSON处理器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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-test</artifactId>
<scope>test</scope>
</dependency>
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<!--thymeleaf对shiro扩展的依赖-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--jedis依赖包-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.4</version>
</dependency>
<!-- shiro+redis缓存插件 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.2.1-RELEASE</version>
</dependency>
<!-- 整合jsp所需依赖,要是添加了thymeleaf似乎会出问题-->
<!--<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>-->
<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
二.添加配置
#tomcat启动端口
server.port=9090
#server.servlet.context-path=/
#自动重启
spring.devtools.restart.enabled=true
#添加额外监听的路径
#spring.devtools.restart.additional-paths=src/main/
#添加忽略目录(排除的路径)
#spring.devtools.restart.exclude=/excludepath/
#实时刷新(通知浏览器实时刷新,要下插件)
spring.devtools.livereload.enabled=true
#mysql配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://xx.xx.xx.xx:3306/xxx?useUnicode=true&characterEncoding=utf8
spring.datasource.username = xxx
spring.datasource.password = xxxx
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10
#mybatis
#把数据库字段的下划线转换成实体类中的驼峰式命名
mybatis.configuration.map-underscore-to-camel-case=true
#mybatis表映射文件目录
mybatis.mapper-locations=classpath:mapper/*.xml
#springmvc
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
#配置分页插件pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params.count=countSql
#禁用thymeleaf缓存
spring.thymeleaf.cache=false
#配置连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#druid监控配置
spring.datasource.filters=stat,wall,log4j
spring.datasource.dbcp2.min-idle=5
#初始化提供的连接数
spring.datasource.dbcp2.initial-size=5
#最大的连接数
spring.datasource.dbcp2.max-total=5
#等待连接获取的最大超时时间
spring.datasource.dbcp2.max-wait-millis=200
##rabbitMQ
#spring.rabbitmq.host=xx.xx.xx.xx
#spring.rabbitmq.port=5672
#spring.rabbitmq.username=user
#spring.rabbitmq.password=user
##redis
#spring.redis.host=xx.xx.xx.xx
#spring.redis.port=6379
#spring.redis.password=xxx
#spring.redis.timeout=1000ms
##lettuce最大连接数
#spring.redis.lettuce.pool.max-active=8
##连接池最大阻塞时间(-1表示没有限制
#spring.redis.lettuce.pool.max-wait=-1ms
##最大空闲连接
#spring.redis.lettuce.pool.max-idle=8
##最小空闲连接
#spring.redis.lettuce.pool.min-idle=0
#
#logging.level.com.seecen=debug
由于springboot还没集成shiro的properties所以要添加配置类,配置类如下(添加配置类之前最好先自定义Realm)
自定义Realm
package com.taotao.shiro;
import com.taotao.pojo.User;
import com.taotao.service.UserService;
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.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
/**
* Author: TaoTao 2019/9/14
*/
@Component
public class UserRealm extends AuthorizingRealm {
private static Logger logger = LoggerFactory.getLogger(UserRealm.class);
@Autowired
private UserService userService;
/**
* 验证身份信息
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
/**
* 验证用户名步骤
* 1.获取令牌中的用户名
* 2.根据用户名去查询是否有该用户
* a.有用户存在
* b.没有,直接抛出异常
* 3.返回一个验证用户名和密码的类对象(封装了md5加密的验证方式)
*/
logger.info("---------------- 执行 Shiro 凭证认证 ----------------------");
String name = (String) token.getPrincipal();
// 从数据库获取对应用户名密码的用户
User userInfo = userService.findUserByNames(name);
if (userInfo != null) {
// 用户为禁用状态
if (userInfo.getuState() != 0) {
throw new DisabledAccountException("账户已被禁用!");
}
logger.info("---------------- Shiro 凭证认证成功 ----------------------");
//md5加密再加盐
//根据表单数据和加密字符串和盐值进行比较验证
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
name, //用户
userInfo.getuPwd(), //密码
ByteSource.Util.bytes(userInfo.getuSal()),//盐值
getName() //realm name
);
// 返回给安全管理器,由 securityManager 比对密码的正确性
return authenticationInfo;
}
throw new UnknownAccountException();
}
/**
* 获取操作权限
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("---------------- 执行 Shiro 权限获取 ---------------------");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//到数据库查询当前登录用户的授权字符串
//获取当前登录用户
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
// User dbUser = userService.find
info.addStringPermission(null);
logger.info("---------------- Shiro 权限获取成功 ----------------------");
return info;
/* String username = (String) principals.getPrimaryPrincipal();
//持久化操作:根据用户名获取角色信息和权限信息
//role: admin manage perms:user:create user :update 模块:权限
Set<String> permissionList = new HashSet<>();
permissionList.add("user:list");
permissionList.add("user:create");
permissionList.add("user:update");
Set<String> roleList = new HashSet<>();
roleList.add("admin");
roleList.add("manager");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(roleList);
authorizationInfo.setStringPermissions(permissionList);
return authorizationInfo;*/
}
}
}
添加配置
package com.taotao.shiro;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Author: TaoTao 2019/9/18
*/
@Configuration
public class ShiroConfig {
/**
* Filter工厂
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/user/login","anon"); //指定路径放行
filterMap.put("/user/loginVer","anon");
//设置为登录跳转的页面
shiroFilterFactoryBean.setLoginUrl("/user/login");
//设置未授权跳转页面
shiroFilterFactoryBean.setUnauthorizedUrl("/user/noAuth");
//授权过滤
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 密码校验规则HashedCredentialsMatcher
* 这个类是为了对密码进行编码的 ,
* 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
* 这个类也负责对form里输入的密码进行编码
* 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 使用md5 算法进行加密
hashedCredentialsMatcher.setHashAlgorithmName("md5");
// 设置散列次数: 加密次数(这个地方没有盐值也不会影响密码对比)
hashedCredentialsMatcher.setHashIterations(3);
return hashedCredentialsMatcher;
}
/**
* 自定义Realm
*/
@Bean(name="userRealms")
public UserRealm getRealm(){
UserRealm userRealm = new UserRealm();
//配置加密方式(不然登录失败)
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return userRealm;
}
/**
* 安全管家
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealms") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 配置ShiroDialect ,用于thymeleaf和shiro标签配合使用
* @return
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
MD5加密加盐
public static void main(String[] args) {
//第一:把用户的密码通过md5算法加密
String password = "uuu";
// String md5String = new Md5Hash(password).toString();//不可逆加密算法
// System.out.println("原密码:"+password);
// System.out.println("md5加密的密码:"+md5String);
// //注册,保存加密后的值
// //登录验证 把表单值动态加密再进行比较uuu
// //第二种:加密同时加点盐
// md5String = new Md5Hash(password,"abc").toString();
// System.out.println("md5加密且加盐后的密码:"+md5String);
//第三种:加密次数 增加破解成本
String md5String;
md5String = new Md5Hash("aaa","9734983ae2c939da48d8bc738d34ffb2",3).toString();
System.out.println("md5加密且加盐,还加加密次数后的密码:"+md5String);
// //第四种:随机盐值,配合加密次数
//// String sal = getRandomString();
// md5String = new Md5Hash(password,"abc",3).toString();
// System.out.println("md5加密且随机颜值,还加加密次数后的密码:"+md5String);
总结
在搭建和权限这块基本没什么问题,我所出现的问题是,将密码加密存入数据库后,用户登入失败,在查询资料后发现没有添加 HashedCredentialsMatcher 配置,
然后一直在纠结数据库中的密码使用了盐值进行加密,然后HashedCredentialsMatcher 中并没有添加盐值,而且在该配置类中修改加密次数也可以登入成功(难道这个配置只是在说我加密了哦,求大佬指点)
来源:oschina
链接:https://my.oschina.net/u/4374940/blog/3390768