SpringBoot 整合Shiro 实现登录验证拦截功能

目录

 

前言:

概念:

源码:

步骤:

(1) 首先我准备一个数据库 shiro_demo 并且新建了一张bos_user 的表

(2)在pom 文件中引入 Shiro 1.5.2 的jar 包

(3) 配置文件中配置数据连接信息

(4)编写Shiro 的配置类

(5) 异常处理类  NyExceptionHandler

扫描二维码关注公众号,回复: 11363002 查看本文章

(6) MyFormAuthenticationFilter

(7) MyHashedCredentialsMatcher

(8) MyRealm

(9) MySessionManager

 (10) MyUserNamePasswordToken

(11)RedisSessionDao

 (12)整个项目路径是这样的!

测试:

(1) 我编写了俩个接口:一个是test 一个是vueLogin

(2)业务逻辑类如下:

(3)在网页上访问一下:http://localhost:8006/test/    鼠标一回车显示的是未登录

参考文章:


前言:

Shiro 安全框架是目前为止作为登录注册最常用的框架,因为它十分的强大简单,提供了认证,授权 ,加密和会话管理等功能。

我们项目的登录功能就集成了Shiro ,如果你也对Shiro感兴趣,一起随着小编看下去吧!

Shiro 官网 :http://shiro.apache.org/

Apache Shiro 1.5.2是当前的稳定版本(Java 1.8+ JVM)。

概念:

图引自:戳这

最简单的Shiro应用:

1.应用代码通过Subject 来进行认证和授权,而Subject 又委托给SecurityManager

2.我们需要给Shiro的SecurityManager 注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

三个核心组件:

Subject, SecurityManagerRealms.
①Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
②SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
③Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

原文:https://www.jianshu.com/p/6abc22ec3cb8

Shiro登录验证的流程:

  1. 调用subject.login() 方法进行登录,其会自动委托给securityManager.login方法进行登录。
  2. 通过SecurityManager进入 realm 中进行判断权限和登录认证
  3. 在 realm 中调用dao 层查询数据库
  4. 获取用户数据
  5. realm 包装原始数据传入SecurityManager。通过SecurityManager调用认证方法,根据login 传入的 token 和 realm 返回的用户真实数据进行比对是否正确。如果不正确抛出各种异常,比如未知用户异常,密码错误,登录次数过多异常等。
  6. 根据返回的异常,各种 try..catch..,没有异常返回,则表示登录成功,反之返回前端 catch 结果。

Shiro 登录认证过程详解:https://blog.csdn.net/caoyang0105/article/details/82769293


1. Shiro认证目的就是判断用户的账号密码是否正确之类的,授权的作用嘛,简单的解释就是给用户赋予相应的权限。

2. 判断一个用户有没有权限访问,无非是拦截URL能否访问,分为以下几个操作

  • 判断当前URL是否需要拦截,不需要则放行,需要则进入下一步
  • 判断用户是否已登陆,有则下一步,无则抛出401未认证
  • 从资源表/权限表读取当前登陆用户的可访问地址,进入下一步
  • 判断是否包含用户当前访问的地址,有则放行,无则抛出403无权限

源码:

链接:https://pan.baidu.com/s/1DxfE-Azg2RZrSS6sDlP59Q 
提取码:01z2 

       同时代码也放入github中,网址:https://github.com/tanghh0410/csdn_blog.git 


 


步骤:

(1) 首先我准备一个数据库 shiro_demo 并且新建了一张bos_user 的表

(2)在pom 文件中引入 Shiro 1.5.2 的jar 包

     <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.5.2</version>
        </dependency>

(3) 配置文件中配置数据连接信息


server.port=8006
# MySQL Database
spring.datasource.url=jdbc:mysql://localhost:3306/shiro_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

shiro.jessionid=sessionId

(4)编写Shiro 的配置类

package com.example.shiro.config;


import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
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.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 *
 */
@Configuration
public class ShiroConfig {
    @Value("${shiro.jessionid}")
    private String jessionId;
    @Value("${spring.datasource.url}")
    public String url;
    @Value("${spring.datasource.username}")
    public String username;
    @Value("${spring.datasource.password}")
    public String password;
    @Value("${spring.datasource.driver-class-name}")
    public String driver;

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        /* 自定义filter注册 */
        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
        filters.put("myAuthc", new MyFormAuthenticationFilter());

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //注意过滤器配置顺序 不能颠倒
        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl

        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/vueLogin", "anon");

        filterChainDefinitionMap.put("/**", "myAuthc");
        //转应配置shiro默认登录界面地址,前后端分离中登录界面跳由前端路由控制,后台仅返回json数据
        shiroFilterFactoryBean.setLoginUrl("/unauth");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public MyRealm realm() {
        MyRealm myRealm = new MyRealm();
        //验证
        MyHashedCredentialsMatcher myHashedCredentialsMatcher = new MyHashedCredentialsMatcher();
        myHashedCredentialsMatcher.setHashAlgorithmName("MD5");
        myRealm.setCredentialsMatcher(myHashedCredentialsMatcher);
        return myRealm;
    }

//    @Bean
//    public JdbcRealm jdbcRealm() {
//        JdbcRealm jdbcRealm = new JdbcRealm();
//        jdbcRealm.setPermissionsLookupEnabled(true);//为了查询权限表,要开启权限查询
//        jdbcRealm.setDataSource(datasource());
//        return jdbcRealm;
//    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm());
        // 自定义缓存实现 使用redis
        // 自定义session管理
        securityManager.setSessionManager(defaultWebSessionManager());
        return securityManager;
    }

    @Bean
    public RedisSessionDao getRedisSessionDao() {
        return new RedisSessionDao();
    }

    /**
     * @return
     * @see DefaultWebSessionManager
     */
    @Bean(name = "sessionManager")
    public DefaultWebSessionManager defaultWebSessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //sessionManager.setCacheManager(cacheManager());
        //12小时
        sessionManager.setGlobalSessionTimeout(43200000);
        sessionManager.setDeleteInvalidSessions(true);
        //关键在这里
        sessionManager.setSessionDAO(getRedisSessionDao());
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdCookie(getSessionIdCookie());
        return sessionManager;
    }

    /**
     * 给shiro的sessionId默认的JSSESSIONID名字改掉
     *
     * @return
     */
    @Bean(name = "sessionIdCookie")
    public SimpleCookie getSessionIdCookie() {
        SimpleCookie simpleCookie = new SimpleCookie(jessionId);
        return simpleCookie;
    }

    /**
     * 自定义sessionManager
     *
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
        MySessionManager mySessionManager = new MySessionManager();
        return mySessionManager;
    }

    /**
     * 开启aop注解支持
     *
     * @param
     * @return
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
     *
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

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

    @Bean(name = "exceptionHandler")
    public HandlerExceptionResolver handlerExceptionResolver() {
        return new MyExceptionHandler();
    }

}

(5) 异常处理类  NyExceptionHandler

package com.example.shiro.config;


import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: tanghh18
 * @Date: 2020/4/6 11:28
 */
public class MyExceptionHandler implements HandlerExceptionResolver {
    private static Logger logger = LoggerFactory.getLogger(MyExceptionHandler.class);
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
        ModelAndView mv = new ModelAndView();
        FastJsonJsonView view = new FastJsonJsonView();
        Map map = new HashMap();
        if (ex instanceof UnauthenticatedException|| ex instanceof IncorrectCredentialsException || ex instanceof AuthenticationException) {
            map.put("msg", "用户名或密码错误");
        } else if (ex instanceof UnauthorizedException) {
            map.put("msg", "无权限");
        } else {
            map.put("msg", ex.getMessage());
            logger.info(ex.getMessage());
            ex.printStackTrace();
        }
        view.setAttributesMap(map);
        mv.setView(view);
        return mv;
    }
}

(6) MyFormAuthenticationFilter

package com.example.shiro.config;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.context.annotation.Bean;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * @Author: tanghh18
 * @Date: 2020/4/6 11:29
 */
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    @Override
    protected AuthenticationToken createToken(String username, String password, ServletRequest request, ServletResponse response) {
        boolean rememberMe = isRememberMe(request);
        String host = getHost(request);
        String loginType = "password";
        if(request.getParameter("loginType")!=null && !"".equals(request.getParameter("loginType").trim())){
            loginType = request.getParameter("loginType");
        }
        return new MyUsernamePasswordToken(username, password,loginType,rememberMe,host);
    }
}

(7) MyHashedCredentialsMatcher

package com.example.shiro.config;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;


/**
 * @Author: tanghh18
 * @Date: 2020/4/6 11:30
 */
public class MyHashedCredentialsMatcher extends HashedCredentialsMatcher {
    @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
       MyUsernamePasswordToken mupt = (MyUsernamePasswordToken)token;
        if ("nopassword".equals(mupt.getLoginType())) {
            return true;
        }else {
            return super.doCredentialsMatch(token, info);
        }
    }
}

(8) MyRealm

package com.example.shiro.config;

import com.example.model.BosUserModel;
import com.example.service.BosUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;


/**
 * @Author: tanghh18
 * @Date: 2020/4/6 11:34
 */
public class MyRealm extends AuthorizingRealm {
    @Autowired
    BosUserService bosUserService;

    /**
     * 授权
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    /**
     * 认证
     *
     * @param arg0
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
        //将父类的AuthenticationToken强转为UsernamePasswordToken(因为需要调用UsernamePasswordToken的方法)
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) arg0;
        //获取用户名
        String uname = usernamePasswordToken.getUsername();
        //模拟通过数据库查询到用户名的密码
        BosUserModel user = bosUserService.findUserModelByName(uname);
        //认证信息(参数填写的是用户输入的用户名和数据库查询的密码)
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(uname, user.getPassword(), getName());
        return info;
    }
}

(9) MySessionManager

package com.example.shiro.config;

import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

/**
 * @Author: tanghh18
 * @Date: 2020/4/6 14:00
 */
public class MySessionManager extends DefaultWebSessionManager {

    private static final String AUTHORIZATION = "Authorization";

    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";

    public MySessionManager() {
        super();
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
        //如果请求头中有 Authorization 则其值为sessionId
        if (!StringUtils.isEmpty(id)) {
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        } else {
            //否则按默认规则从cookie取sessionId
            return super.getSessionId(request, response);
        }
    }
}

 (10) MyUserNamePasswordToken

package com.example.shiro.config;

import org.apache.shiro.authc.UsernamePasswordToken;


/**
 * @Author: tanghh18
 * @Date: 2020/4/6 14:00
 */
public class MyUsernamePasswordToken extends UsernamePasswordToken {
    /**
     * 免密登录/账号密码登录
     */
    private String loginType;

    public MyUsernamePasswordToken() {
        super();
    }
    /**
     * 账号密码登录
     * @param username
     * @param password
     * @param loginType
     * @param rememberMe
     * @param host
     */
    public MyUsernamePasswordToken(String username, String password, String loginType, boolean rememberMe,  String host) {
        super(username, password, rememberMe, host);
        this.loginType = loginType;
    }

    /**
     * 免密登录
     * @param username
     */
    public MyUsernamePasswordToken(String username) {
        super(username, "", false, null);
        this.loginType = "nopassword";
    }

    public MyUsernamePasswordToken(String username, String password) {
        super(username, password, false, null);
        this.loginType ="password";
    }

    public String getLoginType() {
        return loginType;
    }

    public void setLoginType(String loginType) {
        this.loginType = loginType;
    }
}

(11)RedisSessionDao

package com.example.shiro.config;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2018/7/31.
 */
@Service
public class RedisSessionDao extends AbstractSessionDAO {
    /**
     *  Session超时时间,单位为毫秒
     */
    private static Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);
    private long expireTime = 30*60*1000;
    /**
     * Redis操作类,对这个使用不熟悉的,可以参考前面的博客
     */
    @Autowired
    private RedisTemplate redisTemplate;

    public RedisSessionDao() {
        super();
    }

    public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {
        super();
        this.expireTime = expireTime;
        //Long类型不可以会出现异常信息;
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        this.redisTemplate = redisTemplate;
    }

    /**
     * 更新session
     * @param session
     * @throws UnknownSessionException
     */
    @Override
    public void update(Session session) throws UnknownSessionException {
        if (session == null || session.getId() == null) {
            return;
        }
        session.setTimeout(expireTime);
        redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 删除session
     * @param session
     */
    @Override
    public void delete(Session session) {
        if (null == session) {
            return;
        }
        redisTemplate.opsForValue().getOperations().delete(session.getId());
    }


    /**
     * // 获取活跃的session,可以用来统计在线人数,如果要实现这个功能,
     * 可以在将session加入redis时指定一个session前缀,统计的时候则使用keys("session-prefix*")的方式来模糊查找redis中所有的session集合
     * @param
     * @return
     */
    @Override
    public Collection<Session> getActiveSessions() {
        Set keys = redisTemplate.keys("*");
        Collection<Session> activeSessions = new ArrayList<>();
        for (Object o:keys){
            String sessionId = o.toString();
            if(sessionId.equals("SuiteTicket") || sessionId.equals("suite_access_token")){
                continue;
            }
            Session session = (Session) redisTemplate.opsForValue().get(sessionId);
            activeSessions.add(session);
        }
        return activeSessions;
    }

    /**
     * 加入session
     * @param session
     * @return
     */
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        //Long类型不可以会出现异常信息;
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);
        return sessionId;
    }

    /**
     * 读取session
     * @param sessionId
     * @return
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            return null;
        }
        return (Session) redisTemplate.opsForValue().get(sessionId);
    }

    public long getExpireTime() {
        return expireTime;
    }

    public void setExpireTime(long expireTime) {
        this.expireTime = expireTime;
    }

    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        //Long类型不可以会出现异常信息;
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
        this.redisTemplate = redisTemplate;

    }
}

 (12)整个项目路径是这样的!


测试:

(1) 我编写了俩个接口:一个是test 一个是vueLogin

package com.example.controller;


import com.example.model.BosUserModel;
import com.example.service.BosUserService;
import com.example.shiro.config.MyUsernamePasswordToken;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

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

/**
 * @Author: wwc
 * @Date: 2019/3/6 14:26
 * @Version 1.0
 */
@RestController
public class ShiroController {

    @Autowired
    private BosUserService bosUserService;


    @GetMapping(value = "/test")
    public void test(){
        System.out.println("这是测试接口-----");
    }


    /**
     * 登录方法
     *
     * @return
     */
    @GetMapping(value = "/vueLogin")
    public void login(HttpSession session) throws Exception {

        //shiro登录,普通的用户名和密码登录
        Subject subject = SecurityUtils.getSubject();
        BosUserModel user = new BosUserModel();
        user.setId(1);
        user.setUserName("soup_tang");
        user.setPassword("1");
//        user.setPassword("c4ca4238a0b923820dcc509a6f75849b");
        UsernamePasswordToken token = new MyUsernamePasswordToken(user.getUserName(), user.getPassword());
        subject.login(token);
        //用户数据保存到session里
        BosUserModel bosUserModel = bosUserService.findUserModelByName(user.getUserName());
        if(bosUserModel!=null){
            System.out.println("登录成功");
            session.setAttribute("user", bosUserModel);
        }else{
            System.out.println("登录失败");
        }
    }


    /**
     * 未登录,shiro应重定向到登录界面,此处返回未登录状态信息由前端控制跳转页面
     *
     * @return
     */
    @RequestMapping(value = "/unauth")
    @ResponseBody
    public Object unauth() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("msg", "未登录");
        return map;
    }
}

(2)业务逻辑类如下:

package com.example.service.impl;

import com.example.model.BosUserModel;
import com.example.service.BosUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @Author tanghh
 * @Date 2020/4/6 10:49
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BosUserServiceImpl implements BosUserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    /**
     * 根据名字查询用户数据
     * @param name
     * @return
     */
    @Override
    public BosUserModel findUserModelByName(String name) {
        String sql = "select * from bos_user where user_name=?";
        Map map = new HashMap<>();
        map.put("name",name);
        BosUserModel userModel = this.jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<BosUserModel>(BosUserModel.class),name);
        return userModel;
    }
}

(3)在网页上访问一下:http://localhost:8006/test/    鼠标一回车显示的是未登录

 (4)在网页上访问一下:http://localhost:8006/vueLogin/

控制台打印语句:

 

一个接口test 被拦截了  , 一个vueLogin没有被拦截,那么是通过什么方法被拦截的呢?答案在:ShiroConfig类。

我在下面这个类的位置 配置了 vueLogin 不被拦截。

 还有一个问题就是:

可以看到下面这张图我将 密码写成的是md5加密的值,这个时候会出现什么问题呢,往下看:

在我的  MyExceptionHandler 类开始报异常了。

百度一下结果 是因为传过来的密码无法将值hash ,后面将代码改过来就可以了,因为我在下面这个方法中写了将密码转化成md5

使用: user.setPassword("1");

参考文章:

Shiro学习目录贴:https://www.iteye.com/blog/jinnianshilongnian-2018398

猜你喜欢

转载自blog.csdn.net/tangthh123/article/details/105338490