建个项目或者模块,目录结构如下

在pom.xml中加入shiro依赖,其他依赖自行添加(lombok,jpa,mybatis,web,thymeleaf等)

        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-spring</artifactId>            <version>1.4.0</version>        </dependency>

application.properties中的配置

##端口号server.port=8888##数据库配置##数据库地址spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&useSSL=false\  &serverTimezone=GMT%2B8##数据库用户名spring.datasource.username=root##数据库密码spring.datasource.password=Panbing936@##数据库驱动spring.datasource.driver-class-name=com.mysql.jdbc.Driver##validate  加载hibernate时,验证创建数据库表结构##create   每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。##create-drop        加载hibernate时创建,退出是删除表结构##update                 加载hibernate自动更新数据库结构##validate 启动时验证表的结构,不会创建表##none  启动时不做任何操作spring.jpa.hibernate.ddl-auto=update##控制台打印sqlspring.jpa.show-sql=true# 建议在开发时关闭缓存,不然没法看到实时页面spring.thymeleaf.cache=false##去除thymeleaf的html严格校验spring.thymeleaf.mode=LEGACYHTML5#没下面这行配置就会报这个错误#Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

实体类SysMenu.java中的代码

@Entity@Datapublic class SysMenu implements Serializable {    @Id    @GeneratedValue    private Integer menuId;    private String menuName;    @ManyToMany    @JoinTable(name = "SysRoleMenu", joinColumns = {@JoinColumn(name = "menuId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})    private List<SysRole> roleList;}

实体类SysRole.java中的代码

@Entity@Datapublic class SysRole implements Serializable {    @Id    @GeneratedValue    private Integer roleId;    private String roleName;    //多对多关系    @ManyToMany(fetch = FetchType.EAGER)    @JoinTable(name = "SysRoleMenu", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "menuId")})    private List<SysMenu> menuList;    //多对多关系    @ManyToMany    @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "userId")})    private List<SysUser> userList;// 一个角色对应多个用户}

实体类SysUser.java中的代码

@Entity@Datapublic class SysUser implements Serializable {    @Id    @GeneratedValue    private Integer userId;    @NotEmpty    private String userName;    @NotEmpty    private String passWord;    //多对多关系    @ManyToMany(fetch = FetchType.EAGER)    //急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载    //FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载    @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "userId")},            inverseJoinColumns = {@JoinColumn(name = "roleId")})    private List<SysRole> roleList;// 一个用户具有多个角色}

接口UserRepository.java中的代码

public interface UserRepository extends CrudRepository<SysUser,Long> {    SysUser findByUserName(String username);}

下面的代码才是shiro相关的

MyshiroRealm.java

public class MyShiroRealm extends AuthorizingRealm {    @Resource    private UserRepository userRepository;    //授权    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        SysUser userInfo  = (SysUser)principals.getPrimaryPrincipal();        for(SysRole role:userInfo.getRoleList()){            authorizationInfo.addRole(role.getRoleName());            for(SysMenu menu:role.getMenuList()){                authorizationInfo.addStringPermission(menu.getMenuName());            }        }        return authorizationInfo;    }    //认证    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)            throws AuthenticationException {        //获得当前用户的用户名        String username = (String)token.getPrincipal();        System.out.println(token.getCredentials());        //根据用户名找到对象        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法        SysUser userInfo = userRepository.findByUserName(username);        if(userInfo == null){            return null;        }        //这里会去校验密码是否正确        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(                userInfo, //用户名                userInfo.getPassWord(),//密码                getName()        );        return authenticationInfo;    }}

ShiroConfig.java

@Configurationpublic class ShiroConfig {    private final Logger logger = LoggerFactory.getLogger(this.getClass());    @Bean    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {        logger.info("启动shiroFilter--时间是:" + new Date());        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();        shiroFilterFactoryBean.setSecurityManager(securityManager);        //shiro拦截器        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->        //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->        // 配置不被拦截的资源及链接        filterChainDefinitionMap.put("/static/**", "anon");        // 退出过滤器        filterChainDefinitionMap.put("/logout", "logout");        //配置需要认证权限的        filterChainDefinitionMap.put("/**", "authc");        // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面,即本文使用的login.html        shiroFilterFactoryBean.setLoginUrl("/login");        // 登录成功后要跳转的链接        shiroFilterFactoryBean.setSuccessUrl("/index");        //未授权界面        shiroFilterFactoryBean.setUnauthorizedUrl("/403");        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);        return shiroFilterFactoryBean;    }    //自定义身份认证Realm(包含用户名密码校验,权限校验等)    @Bean    public MyShiroRealm myShiroRealm(){        MyShiroRealm myShiroRealm = new MyShiroRealm();        return myShiroRealm;    }    @Bean    public SecurityManager securityManager(){        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();        securityManager.setRealm(myShiroRealm());        return securityManager;    }    //开启shiro aop注解支持,不开启的话权限验证就会失效    @Bean    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);        return authorizationAttributeSourceAdvisor;    }    //配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面    @Bean(name="simpleMappingExceptionResolver")    public SimpleMappingExceptionResolver    createSimpleMappingExceptionResolver() {        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();        Properties mappings = new Properties();        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理        mappings.setProperty("UnauthorizedException","403");        simpleMappingExceptionResolver.setExceptionMappings(mappings);  // None by default        simpleMappingExceptionResolver.setDefaultErrorView("error");    // No default        simpleMappingExceptionResolver.setExceptionAttribute("ex");     // Default is "exception"        return simpleMappingExceptionResolver;    }}

thymeleaf的页面代码

index.html

<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>index<br/><form th:action="@{/logout}" method="post">    <p><input type="submit" value="重新登录"/></p></form><form th:action="@{/select}" method="get">    <p><input type="submit" value="查看"/></p></form><form th:action="@{/delete}" method="get">    <p><input type="submit" value="删除"/></p></form></body></html>

login.html

<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>    <meta charset="UTF-8">    <title>Login</title></head><body>错误信息:<h4 th:text="${msg}"></h4><form action="" method="post">    <p>账号:<input type="text" name="username" value="dalaoyang"/></p>    <p>密码:<input type="text" name="password" value="123"/></p>    <p><input type="submit" value="登录"/></p></form></body></html>

另外三个跳转页面就不贴出来了,panpan账号登录可以查看和删除,用xiaoli账号登录则只有查看而没有删除的权限,代码见下面,sql文件在resources包下

github代码

个人网站