springboot+mybatis+shiro搭建教程(附数据表结构)

翻了下,网上的带持久化结构的教程都没用mybatis的版本,也很少有带数据表结构的,就自己动手写了这么一个教程,接下来废话不多说,上干货

项目结构

首先,把数据表准备好

user(用户表)

userId

用户id

userName

用户名

password

用户密码

salt

盐值

role(角色表)

id

 

role

角色

roleName

角色中文名

  

permission(权限表)

id

 

permission

权限名

url

可访问的url

RolePermission(角色关联权限表)

id

 

roleid

角色id

permissionid

权限id

permissionname

权限名

UserRole(用户关联角色表)

id

 

roleid

角色id

userid

用户id

rolename

角色中文名

 

 

其次,把配置和持久层准备好先

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!--排除默认的tomcat-jdbc-->
        <exclusion>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <version>${spring-boot-version}</version>
</dependency>

<dependency>
    <groupId>net.sourceforge.nekohtml</groupId>
    <artifactId>nekohtml</artifactId>
    <version>1.9.22</version>
</dependency>

<!--        mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>


<!--        mybatis依赖包-->
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

<!--通用mapper-->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>1.1.5</version>
</dependency>

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

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.2.2</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.2.2</version>
</dependency>

<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>2.4.2.1-RELEASE</version>
    <exclusions>
        <exclusion>
            <artifactId>shiro-core</artifactId>
            <groupId>org.apache.shiro</groupId>
        </exclusion>
    </exclusions>
</dependency>

application.yml

我用的是开发环境的配置,怎么使用不同环境配置文件,这里就不多说

server:
  port: 8080
  servlet:
    context-path: /national

spring:

  datasource:
    url: jdbc:mysql://47.658.32.69:3sdzsf306/db_g54uoji_dns?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
    username: rvcootdf
    password: roocvt123R324OOTvxcf
    driver-class-name: com.mysql.jdbc.Driver

    hikari:
      idle-timeout: 100000 #超时时间
      connection-timeout: 1000000 #连接时间
      max-lifetime: -1 #连接最长生命周期
      minimum-idle: 10 #池中维护的最小空闲连接数
      maximum-pool-size: 4000 #最大连接数


  thymeleaf:
#    清除缓存
    cache: false
    prefix: classpath:/html/
    suffix: .html #后缀
    mode: LEGACYHTML5 #非严格模式

  resources:
    static-locations: classpath:/static/

mybatis:
  mapper-locations: classpath:/mapper/*.xml
  type-aliases-package: startApplication.model

logging:
  level:
    startApplication.dao : debug

dao层(基本上都是mybatis代码生成器的东西,没有额外的自定义的方法)

userMapper(用户)
@Mapper
public interface UserMapper {
    int countByExample(UserExample example);

    int deleteByExample(UserExample example);

    int deleteByPrimaryKey(Integer userid);

    /**
     * 新增用户
     * @param record
     * @return
     */
    int insert(User record);

    /**
     * 新增用户
     * @param record
     * @return
     */
    int insertSelective(User record);

    /**
     * 按条件查询用户
     * @param example
     * @return
     */
    List<User> selectByExample(UserExample example);

    /**
     * 根据id查询用户
     * @param userid
     * @return
     */
    User selectByPrimaryKey(Integer userid);

    int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example);

    int updateByExample(@Param("record") User record, @Param("example") UserExample example);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
}
 */
List<User> selectByExample(UserExample example);

/**
 * 根据id查询用户
 * @param userid
 * @return
 */
User selectByPrimaryKey(Integer userid);

int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example);

int updateByExample(@Param("record") User record, @Param("example") UserExample example);

int updateByPrimaryKeySelective(User record);

int updateByPrimaryKey(User record);


UserRole(用户角色)

@Mapper
public interface UserRoleMapper {
    int countByExample(UserRoleExample example);

    int deleteByExample(UserRoleExample example);

    int deleteByPrimaryKey(Integer id);

    /**
     * 插入用户角色
     * @param record
     * @return
     */
    int insert(UserRole record);

    /**
     * 插入用户角色
     * @param record
     * @return
     */
    int insertSelective(UserRole record);

    List<UserRole> selectByExample(UserRoleExample example);

    /**
     * 根据主键查询用户角色
     * @param id
     * @return
     */
    UserRole selectByPrimaryKey(Integer id);

    int updateByExampleSelective(@Param("record") UserRole record, @Param("example") UserRoleExample example);

    int updateByExample(@Param("record") UserRole record, @Param("example") UserRoleExample example);

    int updateByPrimaryKeySelective(UserRole record);

    int updateByPrimaryKey(UserRole record);
}

RolePermissionMapper
@Mapper
public interface RolePermissionMapper {
    int countByExample(RolePermissionExample example);

    int deleteByExample(RolePermissionExample example);

    int deleteByPrimaryKey(Integer id);

    /**
     * 插入角色权限
     * @param record
     * @return
     */
    int insert(RolePermission record);

    /**
     * 插入角色权限
     * @param record
     * @return
     */
    int insertSelective(RolePermission record);

    /**
     * 按条件查询角色权限
     * @param example
     * @return
     */
    List<RolePermission> selectByExample(RolePermissionExample example);

    /**
     * 根据id查询角色权限
     * @param id
     * @return
     */
    RolePermission selectByPrimaryKey(Integer id);

    int updateByExampleSelective(@Param("record") RolePermission record, @Param("example") RolePermissionExample example);

    int updateByExample(@Param("record") RolePermission record, @Param("example") RolePermissionExample example);

    int updateByPrimaryKeySelective(RolePermission record);

    int updateByPrimaryKey(RolePermission record);
}

service层

UserServiceInte
public interface UserServiceInte {

    /**
     * 根据用户名密码查询用户
     * @param userName 用户名
     * @param password 密码
     * @return
     */
    public User getUserByName8Password(String userName,String password);

    /**
     * 用户名是否存在
     * @param userName 用户名
     * @return 存在返回true,不存在返回false
     */
    User getUser(String userName);

    /**
     * 创建用户
     * @param user 用户
     * @return
     */
    int insertUser(User user);
}

RoleServiceInte
public interface RoleServiceInte {

    /**
     * 根据用户id查询角色
     * @param userId 用户id
     * @return
     */
    public List<UserRole> getRoleByUser(int userId);

    /**
     * 添加用户角色
     * @param userRole 用户角色
     * @return
     */
    boolean insertUserRole(UserRole userRole);

    /**
     * 获取角色
     * @param roleId 角色id
     * @return
     */
    Role getRoleById(int roleId);
}


PermissionServiceInte
public interface PermissionServiceInte {

    /**
     * 根据角色id查询权限
     * @param roleId 角色id
     * @return
     */
    public List<RolePermission> getPermissionByRole(int roleId);
}

实现类例子

@Service
public class RoleServiceImpl implements RoleServiceInte {

    @Autowired(required = false)
    private RoleMapper roleMapper;

    @Autowired(required = false)
    private UserRoleMapper userRoleMapper;

    @Override
    public List<UserRole> getRoleByUser(int userId) {
        UserRoleExample userRoleExample = new UserRoleExample();
        UserRoleExample.Criteria criteria = userRoleExample.createCriteria();
        criteria.andUseridEqualTo(userId);
        return userRoleMapper.selectByExample(userRoleExample);
    }

    @Override
    public boolean insertUserRole(UserRole userRole) {
        try {
            userRoleMapper.insertSelective(userRole);
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Role getRoleById(int roleId) {
        return roleMapper.selectByPrimaryKey(roleId);
    }
}

项目配置和持久层都准备好了,接下来我们写shiro的配置

shiroconfig(shiro配置类)


import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import startApplication.util.ShiroRealm;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean(name = "shiroRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public ShiroRealm shiroRealm() {
        ShiroRealm realm = new ShiroRealm();
        return realm;
    }

    @Bean(name = "ehCacheManager")
    @DependsOn("lifecycleBeanPostProcessor")
    public EhCacheManager ehCacheManager(){
        EhCacheManager ehCacheManager = new EhCacheManager();
        return ehCacheManager;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        securityManager.setCacheManager(ehCacheManager());//用户授权/认证信息Cache, 采用EhCache 缓存
        return securityManager;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

        // 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边
        Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionManager.put("/logout", "logout");
        // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        filterChainDefinitionManager.put("/user/**", "authc,roles[user]");
        filterChainDefinitionManager.put("/admin/**", "authc,roles[admin]");
        filterChainDefinitionManager.put("/login", "anon");
        filterChainDefinitionManager.put("/index", "anon");
        filterChainDefinitionManager.put("/ajaxLogin", "anon");
        filterChainDefinitionManager.put("/register","anon");
        filterChainDefinitionManager.put("/**",  "authc,roles[user]");//其他资源全部拦截
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);

        // 被拦截跳转页面
        shiroFilterFactoryBean.setLoginUrl("/index");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/success");
        // 未授权界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/index");

        return shiroFilterFactoryBean;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return aasa;
    }
}

shiroRealm(shiro获取权限以及校验密码)


public class ShiroRealm extends AuthorizingRealm {

    private Logger logger = LoggerFactory.getLogger(ShiroRealm.class);

    @Autowired
    private UserServiceInte userServiceInte;

    @Autowired
    private RoleServiceInte roleServiceInte;

    @Autowired
    private PermissionServiceInte permissionServiceInte;

    /**
     * 登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        logger.info("验证当前Subject时获取到token为:" + token.toString());
        System.out.println("当前的登录密码是:"+token.getPassword());
        User user = userServiceInte.getUserByName8Password(token.getUsername(), String.valueOf(token.getPassword()));

        if (user != null) {
            // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
            List<UserRole> role = roleServiceInte.getRoleByUser(user.getUserid()); //获取用户角色
            List<RolePermission> permissions = new LinkedList<>();
            for(UserRole userRole:role){
                permissions=permissionServiceInte.getPermissionByRole(userRole.getRoleid());
            }
            List<String> roleStrlist=new ArrayList<String>();用户的角色集合
            List<String> perminsStrlist=new ArrayList<String>();//用户的权限集合
            for (UserRole userRole : role) {
                roleStrlist.add(userRole.getRolename());
            }
            for (RolePermission rolePermission : permissions) {
                perminsStrlist.add(rolePermission.getPermissionname());
            }
            user.setUserRoleList(roleStrlist);
            user.setUserPermission(perminsStrlist);
            // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
            System.out.println("验证通过");
            return info;
        }else {
            System.out.println("验证不通过");
            return null;
        }


    }

    /**
     * 权限认证
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("##################执行Shiro权限认证##################");
        User user = (User) principalCollection.getPrimaryPrincipal();
        if (user != null) {
            //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //用户的角色集合
            info.addRoles(user.getUserRoleList());
            //用户的权限集合
            info.addStringPermissions(user.getUserPermission());

            return info;
        }
        // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
        return null;
    }
}

持久层、密码校验、权限验证都已经准备好了,那我们就可以写controller了

这是加密密码的

@RequestMapping("login")
    public Map login(String userName, String password) {
        LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();

        int state = 401;
        String msg = "登录失败";
        try {
            User user = userServiceInte.getUser(userName);
            String pw = userName + password;
            SecurityUtils.getSubject().login( new UsernamePasswordToken(userName,new Md5Hash(pw, user.getSalt(), 3).toString()));
            state = 200;
            msg = "登陆成功";
        } catch (IncorrectCredentialsException e) {
            System.out.println("用户名密码错误");

        } catch (UnknownAccountException e) {
            System.out.println("用户不存在");
        }
        resultMap.put("state", state);
        resultMap.put("msg", msg);
        return resultMap;
    }

这是不加密密码的

@RequestMapping(value = "login",method = RequestMethod.POST)
public String login(HttpServletRequest request, HttpServletResponse response, User user){
    System.out.println("登录");
    try {
        SecurityUtils.getSubject().login( new UsernamePasswordToken(user.getUserName(),user.getPassword()));
    }catch (IncorrectCredentialsException e){
        logger.info(user.getUserName()+"用户密码错误!");
        return "loginError";
    }catch (UnknownAccountException e){
        logger.info(user.getUserName()+",该用户名不存在!");
        return "loginError";
    }
    return "/index";
}

差点忘了代码生成器了,好险

代码生成器

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值