springboot 整合 shiro (使用了 thymeleaf模板引擎)

2021-01-15 03:11

阅读:373

YPE html>

标签:hash   har   out   logo   list   and   can   esc   md5   

数据库结构

技术图片

 

 

 技术图片

 

 技术图片

 

 技术图片

 

 

 

 

1. 项目目录结构

技术图片

 

技术图片

 

 

 

 2. pom.xml 添加依赖


         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4.0.0org.springframework.boot
        spring-boot-starter-parent
        2.2.2.RELEASEcn.xej
    springboot-shiro
    0.0.1-SNAPSHOTspringboot-shiroDemo project for Spring Boot1.8org.springframework.boot
            spring-boot-starter-web
        org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.2mysql
            mysql-connector-java
        org.apache.shiro
            shiro-spring
            1.4.1com.github.theborakompanioni
            thymeleaf-extras-shiro
            2.0.0org.springframework.boot
            spring-boot-starter-thymeleaf
        org.springframework.boot
            spring-boot-devtools
            runtimetruecom.alibaba
            druid
            1.1.13org.projectlombok
            lombok
            trueorg.springframework.boot
            spring-boot-starter-test
            testorg.junit.vintage
                    junit-vintage-engine
                org.springframework.boot
                spring-boot-maven-plugin
            

3. application.yml 配置文件

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/tb_shiro?useUnicode=true&amp&characterEncoding=utf-8&serverTimezone=GMT
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
  thymeleaf:
    cache: false


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

4. User 实体类

package cn.xej.pojo;

import lombok.Data;

@Data
public class User {
    private String userId;
    private String password;
    private String name;
}

5. UserDao接口

package cn.xej.mapper;

import cn.xej.pojo.User;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserDao {

    public User findByUserId(String userId);

    public List queryRolesIdByUserId(String userId);
}

6. UserDao.xml文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

7. UserService接口 

package cn.xej.service;

import cn.xej.pojo.User;

import java.util.List;

public interface UserService {
  // 根据用户id查询该用户 
    public User findByUserId(String userId);
  // 根据用户id获取该用户角色
    public List getRolesIdByUserId(String userId);
}

8. UserServiceimpl接口实现类

package cn.xej.service.impl;

import cn.xej.mapper.UserDao;
import cn.xej.pojo.User;
import cn.xej.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceimpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public User findByUserId(String userId) {

        return userDao.findByUserId(userId);
    }

    @Override
    public List getRolesIdByUserId(String userId) {
        return userDao.queryRolesIdByUserId(userId);
    }
}

9. SpringbootShiroApplication 启动类添加包扫描注解

package cn.xej;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("cn.xej.mapper") // 配置一个或多个包路径,自动的扫描这些包路径下的类,自动的为它们生成代理类。
public class SpringbootShiroApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootShiroApplication.class, args);
    }

}

10. RespObj

package cn.xej.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RespObj {

    private Integer code;
    private String message;
    private Object data;

    public static RespObj build(Integer code,String message,Object data){
        return new RespObj(code,message,data);
    }

}

11. SysController(路由跳转控制器)

package cn.xej.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SysController {
  // 进入到登录页面
    @RequestMapping({"/","/welcome"})
    public String welcome(){
        return "login";
    }
  // 进入到首页(登录成功或游客)
    @RequestMapping("/index")
    public String index(){
        return "index";
    }
    
}

12. UserController(控制器)

package cn.xej.controller;

import cn.xej.common.RespObj;
import cn.xej.pojo.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/user")
public class UserController {
  // 登录用户, 返回json数据,因此要加 @ResponseBody注解
    @PostMapping("/toLogin")
    @ResponseBody
    public RespObj toLogin(String userId, String password, HttpSession session){
     // 1. 获取 主体 subject
        Subject subject = SecurityUtils.getSubject();
     // 2. 将账号和密码进行封装 UsernamePasswordToken token
= new UsernamePasswordToken(userId,password);      // 3. shiro认证,进入自定义UserRealm中 try { subject.login(token);
       // 认证成功,将用户名存到session中,返回json数据 session.setAttribute(
"currentUserName",((User)subject.getPrincipal()).getName()); return RespObj.build(200,"ok",null); } catch (Exception e) { System.out.println("账号或密码错误"); return RespObj.build(500,"账号或密码错误",null); } }   
  
  // 注销用户 @PostMapping(
"/logout") @ResponseBody public RespObj logout(){ Subject subject = SecurityUtils.getSubject(); subject.logout(); return RespObj.build(200,"ok",null); } @RequestMapping("/add") public String add(){ return "pages/add"; } @RequestMapping("/update") public String update(){ return "pages/update"; } }

13. 自定义UserRealm

package cn.xej.config;

import cn.xej.pojo.User;
import cn.xej.service.UserService;
import org.apache.shiro.authc.*;
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.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        User user = (User) principalCollection.getPrimaryPrincipal();

        List roles = userService.getRolesIdByUserId(user.getUserId());
        info.addRoles(roles);

        return info;
    }


    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证");

        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        User user = userService.findByUserId(token.getUsername());

        if(user==null){
            return null;
        }
        return new SimpleAuthenticationInfo(user,user.getPassword(),getName()); 

    // 第一个参数,将会传到授权中进行获取,比如 User user = (User) principalCollection.getPrimaryPrincipal();
    // 第二个参数,是该用户数据库里的密码
    // 第三个参数,是当前类名 } }

14. Shiro配置文件(ShiroConfig)

package cn.xej.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

@Configuration  // 该注解表示该类是 配置类
public class ShiroConfig {
   // 我的所有方法名都是类名的首字母小写,不然要写成 @Bean(name="xxx") xxx是自定义的方法名
    // 配置自定义Realm
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

    // 配置安全管理器,把自定义的Realm添加到安全管理器中
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(UserRealm userRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }

    // 配置Filter工厂,设置对应的过滤条件和跳转条件,把安全管理器添加到Filter工厂中
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        shiroFilterFactoryBean.setLoginUrl("/welcome"); //设置进入登录页面的url
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
     shiroFilterFactoryBean.setSuccessUrl("/index"); //设置登录成功url
      
        Map map = new LinkedHashMap();

     // index和 user/toLogin两个路径不用拦截 map.put(
"/index","anon"); map.put("/user/toLogin","anon"); map.put("/**","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // 强制使用cglib,防止重复代理和可能引起代理出错的问题 defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } }

15. login.html页面 

Title
账号
密码

16. index.html (首页) (当用户没登录时,三元表达式显示游客名字,登录时显示该用户名字,并通过shiro标签执行UserRealm中的授权方法,然后通过该用户的id获取他的角色)

17. 实现用户密码加密

1. 首先在shiro 配置文件中 添加解密规则,如下面的解密凭证器,然后放到UserRealm中

  // shiro 解密凭证器
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(1024);
        return hashedCredentialsMatcher;
    }


    // 配置自定义Realm
    @Bean
    public UserRealm userRealm(HashedCredentialsMatcher hashedCredentialsMatcher){
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return userRealm;
    }

2.然后在UserRealm 认证方法中,返回4个参数

  // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证");

        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        User user = userService.findByUserId(token.getUsername());

        if(user==null){
            return null;
        }
        return new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getUserId()),getName());
        // 第一个参数,将会传到授权中进行获取,比如 User user = (User) principalCollection.getPrimaryPrincipal();
        // 第二个参数,是该用户数据库里的密码
     // 第三个参数,是salt,这里我是用用户id当作盐
     // 第四个参数,是当前类名 
}

3. 最后写个测试方法,产生密码加密

“123” 是用户密码
“teacher1” 是加密的盐
1024 是加密次数
String password1 = new SimpleHash("MD5","123","teacher1",1024).toString(); System.out.println("password1 "+password1);

 

springboot 整合 shiro (使用了 thymeleaf模板引擎)

标签:hash   har   out   logo   list   and   can   esc   md5   

原文地址:https://www.cnblogs.com/Alida/p/12926117.html


评论


亲,登录后才可以留言!