SpringBoot中shiro的使用

shiro的使用

什么都不用说了,我们直接看代码吧!!
pom.xml
导入依赖

 <!-- shiro安全框架 -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.4.0</version>
    </dependency>

Shiro配置类
ShiroConfig

import com.yumbo.shiro.MyRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * @Author: GrainFull
 * @Date: 2021/4/21 21:48
 * @Description: Shiro配置类
 */
@Configuration
public class ShiroConfig {
    private Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    @Bean
    public MyRealm getMyRealm() {
        logger.info("=====准备执行myRealm校验=====");
        return new MyRealm();
    }

    /**
     * 安全管理器
     * 权限管理,配置主要是Realm的管理认证
     *
     * @return
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getMyRealm());
        logger.info("=====securityManager注册完成=====");
        return securityManager;
    }

    /**
     * 注入 Shiro 过滤器
     * Filter工厂,设置对应的过滤条件和跳转条件
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        //定义 shiroFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置自定义的 securityManager安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        //设置默认登录的 URL,身份认证失败会访问该 URL
        shiroFilterFactoryBean.setLoginUrl("/login");
        //设置成功之后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 设置未授权界面,权限认证失败会访问该 URL
        shiroFilterFactoryBean.setUnauthorizedUrl("/login");

        // LinkedHashMap 是有序的,进行顺序拦截器配置
        Map<String, String> map = new LinkedHashMap<>();
        //配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
        //登录 URL 放行
        map.put("/login", "anon");//登录页面放行
        map.put("/doLogin", "anon");//登录请求接口放行
        map.put("/404", "anon");//登录请求接口放行
        map.put("/plugins/**", "anon");//静态文件放行
        //对所有用户认证
        //authc表示需要认证才可以访问
        map.put("/**", "authc");
        // 配置 logout 过滤器
        map.put("/logout", "logout");
        //设置 shiroFilterFactoryBean 的 FilterChainDefinitionMap
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        logger.info("=====shiroFilterFactoryBean注册完成=====");
        return shiroFilterFactoryBean;
    }
}

MyRealm

import com.yumbo.entity.User;
import com.yumbo.service.UserService;
import org.apache.commons.lang3.StringUtils;
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;

/**
 * @Author: GrainFull
 * @Date: 2021/4/21 21:50
 * @Description:
 */
public class MyRealm extends AuthorizingRealm {
    @Autowired(required = false)
    private UserService userService;

    /**
     * 为当前登录成功的用户授予权限和分配角色。
     *
     * @param principalCollection
     * @return AuthorizationInfo 为当前登录成功的用户授予权限和分配角色。
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 给该用户设置角色,角色信息存在 t_role 表中获取
        authorizationInfo.setRoles(null);//从数据库中获取
        // 给该用户设置权限,权限信息存在 t_permission 表中取
        authorizationInfo.setStringPermissions(null);//从数据库中获取
        return authorizationInfo;
    }

    /**
     * 用来验证当前登录的用户,获取认证信息。
     *
     * @param authenticationToken
     * @return AuthenticationInfo 用来验证当前登录的用户,获取认证信息。
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 根据 Token 获取用户名,如果您不知道该 Token 怎么来的,先可以不管,下文会解释
        String username = (String) authenticationToken.getPrincipal();
        // 根据用户名从数据库中查询该用户
        User user = userService.login(username);
        if (StringUtils.isBlank(user.getUsername())) {
            throw new UnknownAccountException("该账号不存在!");
        }
        return new SimpleAuthenticationInfo(username, user.getPassword(), getName());
    }
}

application.yml

server:
  port: 8080
  servlet:
    context-path: /yumbo
  tomcat:
    uri-encoding: UTF-8
    max-threads: 1000
    min-spare-threads: 30

spring:
  ## freemarker
  freemarker:
    suffix: .ftl
    content-type: text/html
    charset: UTF-8
    template-loader-path: classpath:/views/
    settings:
      classic_compatible: true

  ## 启用热部署
  devtools:
    restart:
      enabled: true
      additional-paths: src/main/java

LoginController

import com.yumbo.utils.BaseController;
import com.yumbo.utils.ResultInfo;
import org.apache.shiro.SecurityUtils;
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.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.HtmlUtils;

/**
 * @Author: GrainFull
 * @Date: 2021/4/21 1:08
 * @Description:
 */
@Controller
public class LoginController extends BaseController {
    /**
     * 登录视图
     *
     * @return
     */
    @RequestMapping(value = "login")
    public String login() {
        return "login";
    }

    /**
     * 主页视图
     *
     * @return
     */
    @RequestMapping(value = "index")
    public String index() {
        return "index";
    }

    /**
     * 404视图
     *
     * @return
     */
    @RequestMapping(value = "404")
    public String error() {
        return "404";
    }

    /**
     * 登录
     *
     * @param username
     * @param password
     * @return
     */
    @RequestMapping(value = "doLogin", method = RequestMethod.POST)
    @ResponseBody
    public ResultInfo doLogin(String username, String password) {
        Subject subject = SecurityUtils.getSubject();
        try {
            username = HtmlUtils.htmlEscape(username);
            username = username.trim();
            UsernamePasswordToken token = new UsernamePasswordToken(username, DigestUtils.md5DigestAsHex(password.getBytes()));
            subject.login(token);
            return new ResultInfo("成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();

        }
        return new ResultInfo(300, "失败");
    }

    /**
     * 注销登录
     *
     * @return
     */
    @RequestMapping(value = "logout", method = RequestMethod.GET)
    public String logout() {
        return "login";
    }
}

BaseController

import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author: GrainFull
 * @Date: 2021/4/21 1:19
 * @Description:
 */
public class BaseController {
    @ModelAttribute
    public void preHandler(HttpServletRequest request) {
        request.setAttribute("ctx", request.getContextPath());
    }
}

ResultInfo

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @Author: GrainFull
 * @Date: 2021/4/21 1:08
 * @Description: 响应结果工具类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class ResultInfo {
    private Integer code = 200;
    private String msg = "success";
    private Object data;

    public ResultInfo(String msg) {
        this.msg = msg;
    }

    public ResultInfo(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResultInfo(String msg, Object data) {
        this.msg = msg;
        this.data = data;
    }
}

UserService

import com.yumbo.entity.User;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

/**
 * @Author: GrainFull
 * @Date: 2021/4/21 1:12
 * @Description:
 */
@Service
public class UserService {
    /**
     * 登录
     *
     * @param username
     * @return
     */
    public User login(String username) {
        return new User(1, username, DigestUtils.md5DigestAsHex("123456".getBytes()), "admin", "15535795261", "admin@163.com", "男", "上海"); //这里是我用来测试的,实际上应该从数据库中获取
    }
}

页面
login.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>云博-登录</title>
    <#include "common.ftl"/>
    <link rel="stylesheet" href="${ctx}/plugins/css/login.css" media="all">
    <script type="text/javascript" src="${ctx}/plugins/js/login.js" charset="UTF-8"></script>
</head>
<body class="poster">
<form class="form-horizontal login-container" id="loginForm" role="form" action="${ctx}/doLogin" method="post">
    <h2 class="login_title">云博-登录</h2>
    <div class="form-group">
        <label for="username" class="control-label"></label>
        <div class="col-sm-12">
            <input type="text" class="form-control" name="username" id="username" placeholder="请输入账号">
        </div>
    </div>
    <div class="form-group">
        <label for="password" class="control-label"></label>
        <div class="col-sm-12">
            <input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-12">
            <button type="submit" class="btn btn-default col-sm-12 loginSubmit">登录</button>
        </div>
    </div>
</form>
</body>
</html>

login.js

/**
 * @Author: GrainFull
 * @Date: 2021/4/20 16:14
 * @Description:
 */
charset = "UTF-8"
$(function () {
    $("#loginForm").on("submit", function () {
        var params = $(this).serializeArray();
        var requestUrl = $(this).attr("action");
        $.ajax({
            // url: ctx + "/doLogin",
            url: requestUrl,
            type: "post",
            data: params,
            cache: false,//false是不缓存,true为缓存
            async: true, //true为异步,false为同步
            beforeSend: function () {
                //请求前
                console.log("准备登录请求了..")
            },
            success: function (res) {
                console.log("登陆成功");
                if (res.code == 200) {
                    console.log("登陆成功");
                    window.location.href = ctx + "/index";
                }
            },
            complete: function () {
                //请求结束时
                console.log("登录请求结束了..")
                alert("登录请求结束了..")
            },
            error: function () {
                //请求失败时
                console.log("登录失败..")
            }
        });
    });
});

login.css

/**
 * @Author: GrainFull
 * @Date: 2021/4/20 16:07
 * @Description:
 */
.login-container {
    border-radius: 15px;
    background-clip: padding-box;
    margin: 170px auto;
    width: 350px;
    padding: 35px 35px 35px 35px;
    background-color: transparent;
    border: 1px solid #eaeaea;
    /*阴影设置*/
    box-shadow: 0 0 25px #cac6c6;
    background-color: #FFFFFF;
}

.login_title {
    margin: 0px auto 40px auto;
    text-align: center;
    color: #505458;
}

.loginSubmit {
    width: 100%;
    background: #505458;
    border: none;
    color: #FFFFFF;
}

.poster {
    height: 100%;
    width: 100%;
    /*background: #009688;*/
}

body {
    margin: 0;
}

common.ftl

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="${ctx}/plugins/images/favicon.ico">
<!-- 引入 Bootstrap -->
<link href="${ctx}/plugins/bootstrap-3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link href="${ctx}/plugins/bootstrap-3.3.7/css/bootstrap-theme.min.css" rel="stylesheet">

<!-- HTML5 Shiv 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
<!-- 注意: 如果通过 file://  引入 Respond.js 文件,则该文件无法起效果 -->
<!--[if lt IE 9]>
<script src="${ctx}/plugins/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="${ctx}/plugins/libs/respond/1.4.2/respond.min.js"></script>
<![endif]-->


<!-- jQuery (Bootstrap 的 JavaScript 插件需要引入 jQuery) -->
<script src="${ctx}/plugins/jquery/jquery.js"></script>
<!-- 包括所有已编译的插件 -->
<script src="${ctx}/plugins/bootstrap-3.3.7/js/bootstrap.min.js"></script>

<script type="text/javascript">
    var ctx = "${ctx}";
</script>

index.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>云博-主页</title>
    <#include "common.ftl"/>
</head>
<body>
<h3><i>欢迎使用云博管理系统</i></h3>
</body>
</html>

简单shiro使用,欢迎大家参考借鉴

Security安全框架:https://blog.csdn.net/qq_45742386/article/details/115978867

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值