springboot结合thymeleaf整合shiro

先上项目结构图
在这里插入图123达瓦达瓦片描述

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <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>2.1.2</version>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

创建shiroConfig
这个类主要就是配置一些登录,无权限,开放接口和数据库权限表读取

@Configuration
public class ShiroConfig {

    @Autowired
    private MyRealm realm;
    @Autowired
    private RoleMapper roleMapper;

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置登录跳转路径
        shiroFilterFactoryBean.setLoginUrl("/login");
        //设置无权限跳转路径
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        Map<String,String> map = new HashMap<>();
        //设置首页需要登录访问
        map.put("/index","authc");
        //查询数据库权限表获取权限列表
        List<Role> roleList = roleMapper.findRoleList();
        //将权限列表组装
        roleList.forEach((t)->{
            map.put(t.getPermissonurl(),"roles["+t.getRole()+"]");
        });
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //配置自己的Realm
        securityManager.setRealm(realm);
        return securityManager;
    }

}

MyRealm,主要进行用户和权限验证

@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;

    /**
     * 验证角色权限信息
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取到用户名
        String userName = (String) principalCollection.getPrimaryPrincipal();
        //根据用户名查询用户
        User user = userMapper.findByUserName(userName);
        if (user == null){
            return null;
        }
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //拿到用户role字段
        String role = user.getRole();
        if (StringUtils.isEmpty(role)){
            return null;
        }
        //将用户权限进行组装
        HashSet<String> set = new HashSet<>();
        String[] split = role.split(",");
        for (int i = 0; i < split.length; i++) {
            set.add(split[i]);
        }
        authorizationInfo.setRoles(set);
        return authorizationInfo;
    }

    /**
     * 验证用户名密码
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    	//从token中拿到用户名
        String userName = (String) token.getPrincipal();
        if (userName == null){
            return null;
        }
        //查询用户信息
        User user = userMapper.findByUserName(userName);
        if (user == null){
            return null;
        }
        //传入密码进行验证
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName,user.getPassword(),user.getRealname());
        return simpleAuthenticationInfo;
    }
}

MD5工具类

public class MD5Util {
    /**
     * 加点盐
     */
    private static final String SALT = "tom";

    public static String encode(String password){
        password = password + SALT;
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        }catch (Exception e){
            throw new RuntimeException();
        }
        char[] charArray = password.toCharArray();
        byte[] byteArray = new byte[charArray.length];
        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16){
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

    public static void main(String[] args) {
        String encode = encode("123456");
        System.out.println(encode);
    }

}

登录controller

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String login(){
        return "login";
    }

    @RequestMapping("/userLogin")
    public String userLogin(User user, HttpServletRequest request){
        //获取主题用户
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), MD5Util.encode(user.getPassword()));
        try{
            //调用登录接口,该接口会调用MyRealm中的doGetAuthenticationInfo方法进行用户名密码验证,如果用户名密码比对错误会抛出异常
            subject.login(usernamePasswordToken);
            request.setAttribute("username",user.getUsername());
            return "index";
        }catch (Exception e){
            e.printStackTrace();
            request.setAttribute("error","账号或密码错误");
            return "login";
        }
    }

}

其他controller都是普通接口,直接返回字符串,这里就贴一个

@RestController
@RequestMapping("member")
public class MemberController {

    /**
     * insert
     * @return
     */
    @RequestMapping("/insert")
    public String index(){
        return "insert";
    }

    /**
     * update
     * @return
     */
    @ResponseBody
    @RequestMapping("/update")
    public String open(){
        return "update";
    }

}

数据库表按最简单设计
role表
在这里插入图片描述
user表
在这里插入图片描述
再贴一个mapper类做参考

public interface UserMapper {

    @Select("select id,username,password,realname,role"
            + " from user where username=#{userName}")
    User findByUserName(@Param("userName") String userName);

}

yml文件

spring:
  datasource:
    url: jdbc:mysql://ip:port/shiro?useUnicode=true&amp&characterEncoding=utf-8&serverTimezone=GMT
    username: root
    password: ****
    type: com.alibaba.druid.pool.DruidDataSource
  thymeleaf:
    cache: false
    prefix: classpath:/templates/
    suffix: .ftl

mybatis:
  mapper-locations: classpath:mapping/*.xml
  type-aliases-package: cn.xej.pojo
  configuration:
    map-underscore-to-camel-case: true   # 该配置就是将带有下划线的表字段映射为驼峰格式的实体类属性

整体流程就是:
启动项目会经过ShiroConfig的securityManager,先加载自己的Realm
然后走到ShiroConfig的shiroFilter方法加载我们自己配置的登录,无权限,开放接口和数据库权限配置
1.用户首次访问首页跳转到登录页面
2.点击登录先进入userLogin组装token
3.调用subject的login方法被MyRealm的doGetAuthenticationInfo方法拦截验证登录
4.登录成功则跳转至首页,否则跳转至登录页面回到1
5.登录成功后访问其他需要认证和权限的请求会访问到MyRealm的doGetAuthorizationInfo方法进行用户角色验证,验证通过则正常访问,不通过则跳转至无权限配置的请求
本次分享到这里就结束了,大家可以在此基础上研究更加细化的权限控制缓存等,也就是五张表

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值