Based on Apache Shiro environment SpringBoot simple structures
Persistence layer using MyBatis
1. idea in, the Create New the Project;
2. Spring Initializer selected item, select the SDK, the next step;
3. Fill Group, Artifact, Type (MavenProject) , is a packaging WAR; fill in the Name, the Description, the Package;
4. Add dependent : Core-> lombok; Web-> web ; sql-> mybatis, mysql; next; Finish.
Directory Structure:
The introduction of dependency, pom.xml file follows
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent fmappertory -->
</parent>
<groupId>com.shiro.syy</groupId>
<artifactId>apache-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>apache-shiro</name>
<description>spring boot mybatis shiro </description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</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-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
6. Since the pom.xml set up a database connection pool, so you need to configure the database connection pool, the initial project in order to run successfully. application.properties configuration file as follows:
## database配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=zxcvbnm123
## mybatis配置。依次配置内容是 mybatis实体映射的xml文件;实体类所在包名;打印数据库查询语句。
mybatis.mapper-locations=mappers/*.xml
mybatis.type-aliases-package=com.shiro.syy.model
logging.level.com.shiro.syy.mapper=debug
## 视图解析配置
spring.mvc.view.prefix=/pages/
spring.mvc.view.suffix=.jsp
7. build the table
CREATE DATABASE IF NOT EXISTS shiro;
-- 权限表 --
CREATE TABLE permission(
pid INT (11) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL DEFAULT '',
url VARCHAR(255) DEFAULT '',
PRIMARY KEY (pid)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
INSERT INTO permission VALUES ('1','add','');
INSERT INTO permission VALUES ('2','delete','');
INSERT INTO permission VALUES ('3','edit','');
INSERT INTO permission VALUES ('4','query','');
-- 用户表 --
CREATE TABLE user(
uid INT (11) NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL DEFAULT '',
password VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
INSERT INTO user VALUES ('1','admin','123');
INSERT INTO user VALUES ('2','demo','123');
-- 角色表 --
CREATE TABLE role(
rid INT (11) NOT NULL AUTO_INCREMENT,
rname VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (rid)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
INSERT INTO role VALUE ('1','admin');
INSERT INTO role VALUE ('2','customer');
-- 角色权限表 --
CREATE TABLE permission_role(
rid INT(11) NOT NULL ,
pid INT(11) NOT NULL ,
KEY idx_rid (rid),
KEY idx_pid (pid)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
INSERT INTO permission_role VALUE ('1','1');
INSERT INTO permission_role VALUE ('1','2');
INSERT INTO permission_role VALUE ('1','3');
INSERT INTO permission_role VALUE ('1','4');
INSERT INTO permission_role VALUE ('2','1');
INSERT INTO permission_role VALUE ('2','4');
-- 用户角色表 --
CREATE TABLE user_role(
uid INT(11) NOT NULL ,
rid INT(11) NOT NULL ,
KEY idx_rid (uid),
KEY idx_pid (rid)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
INSERT INTO user_role VALUE ('1','1');
INSERT INTO user_role VALUE ('2','2');
8. entity class
@Data
public class User {
private Integer uid;
private String username;
private String password;
private Set<Role> roles = new HashSet<>();
}
@Data
public class Role {
private Integer rid;
private String rname;
private Set<Permission> permissions = new HashSet<>();
private Set<User> users = new HashSet<>();
}
@Data
public class Permission {
private Integer pid;
private String name;
private String url;
}
9. The entity class - a data table mapping profile UserMapper.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.shiro.syy.mapper.UserMapper">
<!--设置User、Role、Permission对应关系-->
<resultMap id="userMap" type="com.shiro.syy.model.User">
<id property="uid" column="uid" />
<result property="username" column="username" />
<result property="password" column="password" />
<collection property="roles" ofType="com.shiro.syy.model.Role">
<id property="rid" column="rid" />
<result property="rname" column="rname" />
<collection property="permissions" ofType="com.shiro.syy.model.Permission">
<id property="pid" column="pid"/>
<result property="name" column="name" />
<result property="url" column="url" />
</collection>
</collection>
</resultMap>
<select id="findByUsername" parameterType="String" resultMap="userMap">
SELECT u.*,r.*,p.*
FROM user u
INNER JOIN user_role ur on ur.uid = u.uid
INNER JOIN role r on r.rid = ur.rid
INNER JOIN permission_role pr on pr.rid = r.rid
INNER JOIN permission p on p.pid = pr.pid
WHERE u.username = #{username}
</select>
</mapper>
Configuration Data Persistence
public interface UserMapper {
User findByUsername(@Param("username") String username);
}
Configuration Yewuluojiceng
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public User findByUsername(String username) {
return userMapper.findByUsername(username);
}
}
10. The cryptographic checksum configuration rules
public class CredentialMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
//获取当前用户的密码
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String password = new String(usernamePasswordToken.getPassword());
//获取数据库中的密码
String dbPassword = (String)info.getCredentials();
return this.equals(password,dbPassword);
}
}
11. Configure user authentication and permissions verification
public class AuthRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 权限认证,shiro授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//先从session中获取user对象
User user = (User) principalCollection.fromRealm(this.getClass().getName()).iterator().next();
//从当前用户中获取所有的角色
List<String> roleNames = new ArrayList<>();
//从当前用户的角色中获取所有权限
List<String> permissions = new ArrayList<>();
Set<Role> roleSet = user.getRoles();
if(CollectionUtils.isNotEmpty(roleSet)){
for(Role role : roleSet){
roleNames.add(role.getRname());
Set<Permission> permissionSet = role.getPermissions();
if(CollectionUtils.isNotEmpty(permissionSet)){
for(Permission permission:permissionSet){
permissions.add(permission.getName());
}
}
}
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roleNames); //角色
info.addStringPermissions(permissions); //权限
return info;
}
/**
* 身份认证,shiro认证登录
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
User user = userService.findByUsername(username);
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName());
}
}
12. shiro core configurator
/**
* 配置IOC容器的Bean对象
* shiro核心配置器
* 将securityManager、realm包中配置好的对象(身份验证器和密码校验器)注入IOC容器中.
* 当项目启动时,首先初始化ShifroFilter()方法,传入参数SecurityManager进行实例构造,
* 从而初始化SecurityManager,……,最后是自定义的CredentialMatcher密码校验器初始化。
*/
@Configuration
public class ShiroConfiguration {
/**
* 注入ShiroFilter过滤器到IOC容器中
* @param manager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean siroFilter(@Qualifier("securityManager") SecurityManager manager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(manager);
// 设置登录页面、登录成功后跳转的页面、登录失败后跳转的页面
bean.setLoginUrl("/login");
bean.setSuccessUrl("/home");
bean.setUnauthorizedUrl("/unauthorized");
// 设置页面的权限过滤器链,并配置到bean中。
LinkedHashMap<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
//过滤器链有顺序的。
filterChainDefinitionMap.put("/index","authc"); //指定拦截器,登录才可访问
filterChainDefinitionMap.put("/login","anon"); //未验证
filterChainDefinitionMap.put("/loginUser","anon"); //未验证
filterChainDefinitionMap.put("/admin","roles[admin]"); //角色名:admin
filterChainDefinitionMap.put("/edit","perms[edit]"); //权限名:edit
filterChainDefinitionMap.put("/unauthorized","anon"); //未验证
filterChainDefinitionMap.put("/druid/**","anon");
filterChainDefinitionMap.put("/**","user"); //是否登录
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return bean;
}
/**
* 注入SecurityManager对象到IOC容器中,
* 以自定义的验证方式进行用户验证
* @param authRealm
* @return
*/
@Bean("securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(authRealm);
return manager;
}
/**
* 将身份权限验证类注入到IOC容器中
* @param matcher @Qualifier注解表示,使用spring上下文的matcher对象
* @return
*/
@Bean("authRealm")
public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher matcher){
//注入密码校验器
AuthRealm authRealm = new AuthRealm();
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
/**
* 注入密码校验规则类到IOC容器中
* @return
*/
@Bean("credentialMatcher")
public CredentialMatcher credentialMatcher(){
return new CredentialMatcher();
}
/**
* 以下两个类用于设置spring和shiro框架的关联
* 配置advisor,使得Spring通过shiro验证时,使用的是自定义的SecurityManager
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
}
13. The configuration controller
@Controller
public class TestController {
@RequestMapping(value = "/login")
public String login(){
return "login";
}
@RequestMapping(value = "/index")
public String index(){
return "index";
}
@RequestMapping(value = "/logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
if(subject!=null){
subject.logout();
}
return "login";
}
@ResponseBody
@RequestMapping(value = "/admin")
public String admin(){
return "admin success";
}
@ResponseBody
@RequestMapping(value = "/edit")
public String edit(){
return "edit success";
}
@RequestMapping(value = "/loginUser")
public String loginUser(@RequestParam("username") String username,
@RequestParam("password") String password,
HttpSession session){
//获取token令牌
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//获取主体
Subject subject = SecurityUtils.getSubject();
try{
subject.login(token);
User user = (User) subject.getPrincipal();
session.setAttribute("user",user);
return "index";
}catch(AuthenticationException e){
System.out.println(username+":"+password);
System.out.println("账号密码错误");
return "login";
}
}
@RequestMapping(value = "/unauthorized")
public String unauthorized(){ //权限不够
return "unauthorized";
}
}