Springboot整合Shiro:实现身份认证

Springboot整合Shiro:实现登录认证

1.使用到的相关的pom依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wxy97</groupId>
    <artifactId>blog</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>blog</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--spring data jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</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>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--集成Shiro安全认证-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
    </dependencies>

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

</project>

2.创建UserRepository.java接口并继承JpaRepository使用SpringDataJpa自定义的简单查询就是根据方法名来自动生成SQL

UserRepository.java

package com.wxy97.blog.dao;

import com.wxy97.blog.po.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @Author: wxySmile
 * @Date 19-11-10 上午11:55
 */
public interface UserRepository extends JpaRepository<User,Long> {

    User findByUsername(String username);
}

3.对未认证的用户请求进行拦截,跳转到认证页面。新建ShiroConfig配置类

ShiroConfig.java

package com.wxy97.blog.shiro;

import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author: wxySmile
 * @Date 19-11-13 上午9:43
 */
@Configuration
public class ShiroConfig {

    /**
     * @Bean 声明创建对象  并把对象放在工厂中  相当于bean标签
     * 如果形参类型对应的对象在工厂中有  会自动装配上
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultSecurityManager defaultSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        /**
         * 过滤器链 过滤拦截规则 哪些页面拦截  哪些页面不拦截
         */
        Map map = new HashMap();
        /**
         * anon 代表匿名可访问 就是不用登录就可以访问  登录页面  登录的url
         * authc 认证可访问 代表登录后才能访问
         *
         * 支持通配符*
         * 注意拦截规则 一个一个配置
         */
        map.put("/admin","anon");
        map.put("/admin/login","anon");

        map.put("/*","authc");
        map.put("/admin/**","authc");
        //默认登录页面
        shiroFilterFactoryBean.setLoginUrl("/admin");
        //认证成功跳转的页面
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        /**
         * 设置安全管理器,将创建的安全管理器放进shiroFilterFactoryBean过滤工厂里面
         */
        shiroFilterFactoryBean.setSecurityManager(defaultSecurityManager);
        return shiroFilterFactoryBean;
    }

    /**
     * 创建安全管理器,并将自定义的Realm放进去管理器
     * @return
     */
    @Bean
    public DefaultSecurityManager getDefaultSecurityManager(MyRealm myRealm){
        DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
//        需要赋值一个Realm
        defaultSecurityManager.setRealm(myRealm);
        return defaultSecurityManager;
    }

    /**
     * 创建自定义的Realm
     */
    @Bean
    public MyRealm getMyRealm(){
        return new MyRealm();
    }
}

4.SecurityManager安全管理器需要到realm中去验证认证信息,所以给SecurityManager设置Realm。我们这里使用自定义的realm实现业务逻辑。新建自定义MyRealm类CustomRealm继承AuthorizingRealm

MyRealm.java

package com.wxy97.blog.shiro;

import com.wxy97.blog.dao.UserRepository;
import com.wxy97.blog.po.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @Author: wxySmile
 * @Date 19-11-13 上午9:39
 */
public class MyRealm extends AuthenticatingRealm {

    @Autowired
    UserRepository userRepository;
    //重写AuthorizingRealm中的认证方法doGetAuthenticationInfo。
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken= (UsernamePasswordToken) authenticationToken;
        User user = userRepository.findByUsername(usernamePasswordToken.getUsername());
        return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName()) ;
    }
}

5.主体提交认证信息,即登录请求

LoginController.java

package com.wxy97.blog.web.admin;

import com.wxy97.blog.po.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.HashMap;

/**
 * @Author: wxySmile
 * @Date 19-11-10 下午12:19
 */
@Controller
@RequestMapping("/admin")
@Api("管理员")
public class LoginController {

    @GetMapping
    @ApiOperation("跳转后台登录页面")
    public String loginPage(){
        return "admin/login";
    }

    @GetMapping("index")
    @ApiOperation("登陆成功跳转后台首页")
    public String index(){
        return "admin/index";
    }

    @PostMapping("/login")
    @ApiOperation("登录校验功能")
    @ResponseBody()
    public HashMap<String, Object>  login(@RequestParam String username, @RequestParam String password, HttpSession session){
        HashMap<String, Object> map = new HashMap<>();
        SimpleHash simpleHash = new SimpleHash("MD5",password,username,1024);
        UsernamePasswordToken token = new UsernamePasswordToken(username, simpleHash.toString());
        Subject subject = SecurityUtils.getSubject();
        try {
            //完成登录
            subject.login(token);
            //获得用户对象
            User user = (User) subject.getPrincipal();
            //存入session
            session.setAttribute("user",user);
            map.put("status","ok");
            map.put("msg","success");
        } catch (AuthenticationException e) {
            //登录失败
            e.printStackTrace();
            map.put("status","error");
            map.put("msg","登录失败!账号或者密码错误");
        }
        return map;
    }

    @GetMapping("loginOut")
    @ApiOperation("退出功能")
    public String loginOut(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "admin/login";
    }

    public static void main(String[] args) {
        //明码
        String password = "admin";
        //加密算法
        String algorithmName = "MD5";
        //要加密的密码
        Object source = password;
        //盐值,一般都是用户名或者userid,要保证唯一
        Object salt = "admin";
        //加密次数
        int hashIterations = 1024;
        SimpleHash simpleHash = new SimpleHash(algorithmName,source,salt,hashIterations);
        //打印出经过盐值、加密次数、md5后的密码
        System.out.println(simpleHash.toString());
    }

}

6.前台页面发送ajax并作出响应

login.html

<!DOCTYPE html>
<html lang="en" class="page-fill">
<head>
    <meta charset="UTF-8">
    <title>wxySmile后台登录</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="shortcut icon" href="../../images/favicon.ico" type="image/x-icon"/>
    <link rel="stylesheet" href="../../css/oksub.css"/>
</head>
<body class="page-fill">
    <div class="page-fill" id="login">
        <form class="layui-form">
            <div class="login_face"><img src="../images/logo.png"></div>
            <div class="layui-form-item input-item">
                <label for="username">用户名</label>
                <input type="text" lay-verify="required" name="username" placeholder="请输入账号" autocomplete="off" id="username" class="layui-input">
            </div>
            <div class="layui-form-item input-item">
                <label for="password">密码</label>
                <input type="password" lay-verify="required|password" name="password" placeholder="请输入密码" autocomplete="off" id="password" class="layui-input">
            </div>
            <div class="layui-form-item">
                <button class="layui-btn layui-block" lay-filter="login" lay-submit="">登录</button>
            </div>
            <div class="login-link">
                <a href="register.html">忘记密码?</a>
            </div>
        </form>
    </div>
    <!--js逻辑-->
    <script src="../../lib/layui/layui.js"></script>
    <script>
        layui.use(["form"], function () {
            let form = layui.form;
            let $ = layui.jquery;
            /**
             * 数据校验
             */
            form.verify({
                password: [/^[\S]{5,12}$/, "密码必须5到12位,且不能出现空格"],
            });

            /**
             * 表单提交
             */
            form.on("submit(login)", function (data) {
                $.ajax({
                    url:'/admin/login',
                    method:'post',
                    data:data.field,
                    dataType:'json',
                    success:function (data) {
                        if (data.status=='ok'){
                            //登陆成功
                            window.location.href='admin/index'
                        } else {
                            //登录失败
                            layer.open({
                                icon:5,
                                anim:6,
                                time:2500,
                                title: data.status,
                                content: data.msg
                            });

                        }
                    }
                })
                return false;
            });

            /**
             * 表单input组件单击时
             */
            $("#login .input-item .layui-input").click(function (e) {
                e.stopPropagation();
                $(this).addClass("layui-input-focus").find(".layui-input").focus();
            });

            /**
             * 表单input组件获取焦点时
             */
            $("#login .layui-form-item .layui-input").focus(function () {
                $(this).parent().addClass("layui-input-focus");
            });

            /**
             * 表单input组件失去焦点时
             */
            $("#login .layui-form-item .layui-input").blur(function () {
                $(this).parent().removeClass("layui-input-focus");
                if ($(this).val() != "") {
                    $(this).parent().addClass("layui-input-active");
                } else {
                    $(this).parent().removeClass("layui-input-active");
                }
            })
        });
    </script>
</body>
</html>

7.运行测试

最后修改:2019 年 11 月 15 日 11 : 50 PM
如果觉得我的文章对你有用,请随意赞赏

发表评论

3 条评论

  1. 123

    <script>alert(1)</script>

  2. 123

    <script type="text/javascript">

    alert('着了'+i); &lt;/script&gt;
  3. 123

    <script type="text/javascript">

    for (var i = 100; i >= 0; i--) { alert('着了'+i); } </script>