访问start.spring.io生成项目:
然后选择依赖:
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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.20.RELEASE</version> <relativePath /> </parent> <groupId>org.dreamtech</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>demo</name> <description>Demo project for Apache Shiro</description> <properties> <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>1.3.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </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-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <!-- Druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.14</version> </dependency> <!-- 配合依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.2.3.RELEASE</version> </dependency> <!-- JSP --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</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>
数据库:
/* * 使用数据库shiro_demo */ USE shiro_demo; /* * 权限表 */ 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','admin'); INSERT INTO user VALUES ('2','xuyiqing','xuyiqing'); /* * 角色表 */ 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 VALUES ('1','admin'); INSERT INTO role VALUES ('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 VALUES ('1','1'); INSERT INTO permission_role VALUES ('1','2'); INSERT INTO permission_role VALUES ('1','3'); INSERT INTO permission_role VALUES ('1','4'); INSERT INTO permission_role VALUES ('2','1'); INSERT INTO permission_role VALUES ('2','4'); /* * 用户角色关系表 */ CREATE TABLE user_role( uid INT(11) NOT NULL, rid INT(11) NOT NULL, KEY idx_uid (uid), KEY idx_pid (rid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user_role VALUES ('1','1'); INSERT INTO user_role VALUES ('2','2');
实体类:
Permission:
package org.dreamtech.demo.model; public class Permission { private Integer pid; private String name; private String url; public Integer getPid() { return pid; } public void setPid(Integer pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
Role:
package org.dreamtech.demo.model; import java.util.HashSet; import java.util.Set; public class Role { private Integer rid; private String rname; private Set<Permission> permissions = new HashSet<Permission>(); private Set<User> users = new HashSet<User>(); public Integer getRid() { return rid; } public void setRid(Integer rid) { this.rid = rid; } public String getName() { return rname; } public void setName(String rname) { this.rname = rname; } public Set<Permission> getPermissions() { return permissions; } public void setPermissions(Set<Permission> permissions) { this.permissions = permissions; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } }
User:
package org.dreamtech.demo.model; import java.util.HashSet; import java.util.Set; public class User { private Integer uid; private String username; private String password; private Set<Role> roles = new HashSet<Role>(); public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } 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 Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
application.properties:
# tomcat server.tomcat.uri-encoding=UTF-8 # server server.port=80 # database spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.drive-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/shiro_demo?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=xuyiqing # mybatis mybatis.mapper-locations=mappers/*.xml mybatis.type-aliases-package=org.dreamtech.demo.model # jsp spring.mvc.view.prefix=/pages/ spring.mvc.view.suffix=.jsp
Mapper:
package org.dreamtech.demo.mapper; import org.apache.ibatis.annotations.Param; import org.dreamtech.demo.model.User; public interface UserMapper { User findByUsername(@Param("username") String username); }
<?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="org.dreamtech.demo.mapper.UserMapper"> <resultMap type="org.dreamtech.demo.model.User" id="userMap"> <id property="uid" column="uid" /> <result property="username" column="username" /> <result property="password" column="password" /> <collection property="roles" ofType="org.dreamtech.demo.model.Role"> <id property="rid" column="rid" /> <result property="rname" column="rname" /> <collection property="permissions" ofType="org.dreamtech.demo.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>
Service:
package org.dreamtech.demo.service; import org.dreamtech.demo.model.User; public interface UserService { User findByUsername(String username); }
package org.dreamtech.demo.service.impl; import org.dreamtech.demo.mapper.UserMapper; import org.dreamtech.demo.model.User; import org.dreamtech.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findByUsername(String username) { return userMapper.findByUsername(username); } }
Controller:
package org.dreamtech.demo.controller; import javax.servlet.http.HttpSession; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.dreamtech.demo.model.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class TestController { @RequestMapping("/login") public String login() { return "login"; } @RequestMapping("/index") public String index() { return "index"; } @RequestMapping("/admin") @ResponseBody public String admin() { return "admin success"; } @RequestMapping("/edit") @ResponseBody public String edit() { return "edit success"; } @RequestMapping("/unauthorized") @ResponseBody public String unAuthorized() { return "没有权限访问"; } @RequestMapping("/logout") public String logout() { Subject subject = SecurityUtils.getSubject(); if (subject != null) { subject.logout(); } return "login"; } @RequestMapping("/loginuser") public String loginUser(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session) { 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 (Exception e) { System.out.println("用户名或密码错误"); return "login"; } } }
Shiro配置:
package org.dreamtech.demo; import java.util.LinkedHashMap; import org.apache.shiro.cache.MemoryConstrainedCacheManager; 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.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Shiro配置 * * @author Xu Yiqing * */ @Configuration public class ShiroConfiguration { @Bean("credentialMatcher") public CredentialMatcher credentialMatcher() { return new CredentialMatcher(); } @Bean("authRealm") public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher matcher) { AuthRealm authRealm = new AuthRealm(); authRealm.setCredentialsMatcher(matcher); // 设置缓存在内存中 authRealm.setCacheManager(new MemoryConstrainedCacheManager()); return authRealm; } @Bean("securityManager") public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm realm) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(realm); return manager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(manager); // 登陆路径/login bean.setLoginUrl("/login"); // 登陆成功路径/index bean.setSuccessUrl("/index"); // 权限不足或认证失败路径/unauthorized bean.setUnauthorizedUrl("/unauthorized"); LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 需要经过身份认证才可以访问/index filterChainDefinitionMap.put("/index", "authc"); // 可以匿名使用 filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/loginuser", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); // 登陆后的所有角色都可以访问/** filterChainDefinitionMap.put("/**", "user"); // 只有admin角色才可以访问/admin filterChainDefinitionMap.put("/admin", "roles[admin]"); // 只有拿到edit权限的用户才可以访问/edit filterChainDefinitionMap.put("/edit", "perms[edit]"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); return bean; } @Bean("authorizationAttributeSourceAdvisor") public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( @Qualifier("securityManager") SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } /** * 实现Spring的自动代理 * * @return */ @Bean("defaultAdvisorAutoProxyCreator") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } }
package org.dreamtech.demo; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.SimpleCredentialsMatcher; 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); } }
package org.dreamtech.demo; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.commons.collections.CollectionUtils; 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.dreamtech.demo.model.Permission; import org.dreamtech.demo.model.Role; import org.dreamtech.demo.model.User; import org.dreamtech.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 认证 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next(); List<String> permissionList = new ArrayList<String>(); List<String> roleNameList= new ArrayList<String>(); Set<Role> roleSet = user.getRoles(); if (CollectionUtils.isNotEmpty(roleSet)) { for (Role role : roleSet) { roleNameList.add(role.getName()); Set<Permission> permissionSet = role.getPermissions(); if (CollectionUtils.isNotEmpty(permissionSet)) { for (Permission permission : permissionSet) { permissionList.add(permission.getName()); } } } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermissions(permissionList); info.addRoles(roleNameList); return info; } /** * 授权登陆 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; String username = usernamePasswordToken.getUsername(); User user = userService.findByUsername(username); return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName()); } }
Druid配置:
package org.dreamtech.demo; import javax.sql.DataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; /** * Druid连接池的配置 * * @author Xu Yiqing * */ @Configuration public class DruidConfiguration { /** * 给Druid注册Servlet * * @return */ @Bean public ServletRegistrationBean statViewServlet() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); // 白名单 servletRegistrationBean.addInitParameter("allow", "127.0.0.1"); // IP黑名单 servletRegistrationBean.addInitParameter("deny", "192.168.1.100"); // 登录查看信息的账号密码. servletRegistrationBean.addInitParameter("loginUsername", "druid"); servletRegistrationBean.addInitParameter("loginPassword", "xuyiqing"); // 是否能够重置数据. servletRegistrationBean.addInitParameter("resetEnable", "false"); return servletRegistrationBean; } /** * 给Druid注册Filter * * @return */ @Bean public FilterRegistrationBean statFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); // 添加过滤规则 filterRegistrationBean.addUrlPatterns("/*"); // 添加不需要忽略的格式信息 filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean; } /** * 配置持久性异常转换后处理器(翻译过来的) * * @return */ @Bean public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() { return new PersistenceExceptionTranslationPostProcessor(); } /** * 配置数据库的基本连接信息 * * @return */ @Bean(name = "dataSource") @Primary @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DataSourceBuilder.create().type(com.alibaba.druid.pool.DruidDataSource.class).build(); } /** * 配置SqlSessionFactoryBean * * @param dataSource * @return * @throws Exception */ @Bean public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); bean.setMapperLocations(resolver.getResources("classpath:/mappers/*.xml")); return bean; } }
页面:webapp/pages/*
首页
<%@ page language="java" contentType="text/html; charset=UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Home</title> </head> <body> <h1>欢迎登陆:${user.username}</h1> </body> </html>
登陆
<%@ page language="java" contentType="text/html; charset=UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <h1>欢迎登陆</h1> <form action="/loginuser" method="post"> <input type="text" name="username"><br /> <input type="password" name="password"><br /> <input type="submit" value="登陆"> </form> </body> </html>