pom.xml
4.0.0
com.soneer
fp
0.0.1-SNAPSHOT
jar
fp
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-validation
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
org.springframework.boot
spring-boot-starter-aop
2.0.4.RELEASE
org.springframework.boot
spring-boot-starter-thymeleaf
2.0.4.RELEASE
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
org.mybatis.generator
mybatis-generator-core
1.3.5
com.alibaba
druid-spring-boot-starter
1.1.10
com.github.pagehelper
pagehelper-spring-boot-starter
1.2.5
org.apache.shiro
shiro-spring
1.4.0
org.springframework.boot
spring-boot-maven-plugin
com.soneer.fp.FpApplication
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.5
true
true
mysql
mysql-connector-java
5.1.46
application.properties
server.port=8888
# Generator逆向工程
#generator.targetProject=src/main/java
#generator.javaModel-targetPackage=com.soneer.fp.pojo
#generator.sqlMap-targetPackage=com.soneer.fp.mapper
#generator.javaClient-targetPackage=com.soneer.fp.mapper
#thymelea模板配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false//开发环境设为false,生产环节根据需要去设置
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
mybatis.mapper-locations=classpath:mapper/*.xml
#durid连接池
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.druid.url = jdbc:mysql://localhost:3306/sone
spring.datasource.druid.username=root
spring.datasource.druid.password=sone920801
#初始化时建立物理连接的个数,初始化发生在显示调用init方法,或者第一次getConnection时
spring.datasource.druid.initial-size=5
#最大连接池数量
spring.datasource.druid.max-active=100
#最小连接池数量
spring.datasource.druid.min-idle=5
#获取连接时最大等待时间,单位毫秒
spring.datasource.druid.max-wait=60000
#是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
#用来检测连接是否有效的sql,要求是一个查询语句
spring.datasource.druid.validation-query=SELECT * FROM user
spring.datasource.druid.validation-query-timeout=60000
#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
spring.datasource.druid.test-on-borrow=false
#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
spring.datasource.druid.test-on-return=false
#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
spring.datasource.druid.test-while-idle=true
# 有两个含义:
#1) Destroy线程会检测连接的间隔时间
# 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=100000
# WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
spring.datasource.druid.stat-view-servlet.enabled= true
spring.datasource.druid.stat-view-servlet.url-pattern= /druid/*
spring.datasource.druid.stat-view-servlet.reset-enable= false
spring.datasource.druid.stat-view-servlet.login-username= admin
spring.datasource.druid.stat-view-servlet.login-password= admin
spring.datasource.druid.stat-view-servlet.allow= 127.0.0.1
#spring.datasource.druid.stat-view-servlet.deny= 192.168.32.139 #访问黑名单
# 配置StatFilter
spring.datasource.druid.filter.stat.db-type=mysql
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=5000
# 配置WallFilter
spring.datasource.druid.filter.wall.enabled=true
spring.datasource.druid.filter.wall.db-type=mysql
spring.datasource.druid.filter.wall.config.delete-allow=false
spring.datasource.druid.filter.wall.config.drop-table-allow=false
#pagehelper分页
logging.level.com.soneer.fp.service=DEBUG
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
pagehelper.page-size-zero=true
目录结构
这里圈出来的不用管它,pom和application文件都已经去除配置了。
cosrConfig里面是用于跨域配置的。
annotation里面是我自定义的注解。
author里面是通过aop来做api调用身份认证的(相关的依赖和配置均已去除,且不管它)。
下面进入正题!
DruidConfig类
package com.soneer.fp.datasource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import javax.sql.DataSource;
@Configuration
@ConditionalOnClass(com.alibaba.druid.pool.DruidDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = true)
public class DruidConfig {
/**
* @see
* @return DruidDataSource
*/
@Bean
@ConfigurationProperties("spring.datasource.druid")
public DataSource dataSourceOne(){
return DruidDataSourceBuilder.create().build();
}
}
DruidStatFilter类
package com.soneer.fp.datasource;
import com.alibaba.druid.support.http.WebStatFilter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
/**
* Servlet Filter implementation class DruidFilter
*/
@WebFilter(
filterName="druidWebStatFilter",
urlPatterns= {"/*"},
initParams= {
@WebInitParam(name="exclusions",value="*.js,*.jpg,*.png,*.gif,*.ico,*.css,/druid/*")//配置本过滤器放行的请求后缀
}
)
public class DruidStatFilter extends WebStatFilter {
}
DruidStatViewServlet 类
package com.soneer.fp.datasource;
import com.alibaba.druid.support.http.StatViewServlet;
import javax.servlet.Servlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
/**
* Servlet implementation class DruidStateViewServlet
*/
@WebServlet(
urlPatterns= {"/druid/*"},
initParams= {
@WebInitParam(name="allow",value="127.0.0.1"),
@WebInitParam(name="loginUsername",value="root"),
@WebInitParam(name="loginPassword",value="123"),
@WebInitParam(name="resetEnable",value="true")// 允许HTML页面上的“Reset All”功能
}
)
public class DruidStatViewServlet extends StatViewServlet implements Servlet {
private static final long serialVersionUID = 1L;
}
LoginUser类
package com.soneer.fp.pojo;
import java.io.Serializable;
public class LoginUser implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int userId;
private String userName;
private String trueName;
private String userType;
private String password;
private String duty;
private String unit;
private String phone;
private int rolesId;
private Integer bfId;
private Integer approles;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getTrueName() {
return trueName;
}
public void setTrueName(String trueName) {
this.trueName = trueName;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDuty() {
return duty;
}
public void setDuty(String duty) {
this.duty = duty;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getRolesId() {
return rolesId;
}
public void setRolesId(int rolesId) {
this.rolesId = rolesId;
}
public Integer getBfId() {
return bfId;
}
public void setBfId(Integer bfId) {
this.bfId = bfId;
}
public Integer getApproles() {
return approles;
}
public void setApproles(Integer approles) {
this.approles = approles;
}
@Override
public String toString() {
return "LoginUser [userId=" + userId + ", userName=" + userName + ", trueName=" + trueName + ", userType="
+ userType + ", password=" + password + ", duty=" + duty + ", unit=" + unit + ", phone=" + phone
+ ", rolesId=" + rolesId + ", bfId=" + bfId + ", approles=" + approles + "]";
}
}
ShiroConfig类
package com.soneer.fp.shiro;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.mgt.SecurityManager;
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 javax.annotation.Resource;
/**
* Shiro配置类
* 1.配置ShiroFilterFactory 2.配置SecurityManager
* @author zhengkai
*
*/
@Configuration
public class ShiroConfig {
@Resource
private UserRealm userRealm;
/**
* 配置shiro过滤器
* @author zhengkai
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager securityManager) {
//1.定义shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//2.设置securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//3.LinkedHashMap是有序的,进行顺序拦截器配置
Map filterChainMap = new LinkedHashMap();
//4.配置logout过滤器
filterChainMap.put("/logout", "logout");
//登陆和主页不需要认证
filterChainMap.put("/login","anon");
filterChainMap.put("/","anon");
filterChainMap.put("/checkLogin","anon");
filterChainMap.put("/css/**", "anon"); //匿名访问静态资源
filterChainMap.put("/js/**", "anon"); //匿名访问静态资源
filterChainMap.put("/fonts/**", "anon"); //匿名访问静态资源
filterChainMap.put("/images/**", "anon"); //匿名访问静态资源
filterChainMap.put("/lib/**", "anon"); //匿名访问静态资源
//5.所有url必须通过认证才可以访问
filterChainMap.put("/**","authc");
//6.设置默认登录的url
shiroFilterFactoryBean.setLoginUrl("/login");
//7.设置成功之后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//8.设置未授权界面
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
//9.设置shiroFilterFactoryBean的FilterChainDefinitionMap
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
return shiroFilterFactoryBean;
}
/**
* 配置安全管理器
* @author zhengkai
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置realm.
securityManager.setRealm(userRealm);//将自定义的realm注入到securityManager中
return securityManager;
}
}
自定义UserRealm类
package com.soneer.fp.shiro;
import javax.annotation.Resource;
import com.soneer.fp.pojo.LoginUser;
import com.soneer.fp.service.impl.LoginUserBizImpl;
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.UsernamePasswordToken;
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.jboss.logging.Logger;
import org.springframework.stereotype.Component;
@Component
public class UserRealm extends AuthorizingRealm {
private Logger logger=Logger.getLogger(getClass());
@Resource
private LoginUserBizImpl userBiz;
//用户角色和权限授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection Principal){
String userName=(String)Principal.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
try {
authorizationInfo.setRoles(userBiz.chkRoleName(userName));
authorizationInfo.setStringPermissions(userBiz.chkPermissions(userName));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(authorizationInfo);
return authorizationInfo;
}
//用户身份登陆认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String userName = token.getUsername();
logger.info("doGetAuthenticationInfo username--------->:"+userName);
String username=(String)token.getPrincipal();
//String username=userName;
try {
LoginUser user=userBiz.chkByUserName(username);
if(user!=null){
//System.out.println(user.getUserName()+"===="+user.getPassword());
AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),"userRealm");
return authcInfo;
}else {
return null;
}
} catch (Exception e) {
System.out.println("身份认证失败");
}
return null;
}
}
可能有的人注意到了上面注解@Component 这里是要将UserRealm这个类注入到securityManager中才能起到作用,这里我一开始在上面的ShiroCongfig类中没有将自定义UserRealm这个类注入进去,导致报错No realms have been configured! One or more realms must be 。。。。
LoginUserMapper
import com.soneer.fp.pojo.LoginUser;
import org.apache.ibatis.annotations.Param;
public interface LoginUserMapper {
/**
*
* @param username
* @param password
* @return
*/
LoginUser loginByuser(@Param("username") String username, @Param("password") String password);
/**
*
* @param username
* @return
*/
LoginUser chkByUserName(@Param("username") String username);
/**
*
* @return
* @param username
*/
Set chkRoleName(@Param("username") String username);
/**
*
* @param username
* @return
* @throws Exception
*/
Set chkPermissions(String username);
}
LoginUserMapper.xml