springboot集成shiro实现注册、登录、退出功能

Shiro中的认证对象

- Subject 主体

访问系统的用户。主体可以是用户、程序等,进行认证的都称为主体。

- Principal 身份信息

是主体进行身份认证的标识,标识具有唯一性,如用户名、手机号、邮箱等,一个主体可以有多个身份,但必须有一个主身份。

- Credential 凭证信息

是只有主体自己知道的安全信息,如密码、证书等。

Shiro的认证过程

首先主体需要携带身份信息和凭证信息,比如用户名和密码,然后Shiro会将这些信息包装成一个令牌,也就是Token,然后再通过Shiro中的安全管理器进行认证。安全管理器再调用认证器,认证器再去调用Realm获取数据。将携带的身份信息和凭证信息与原始数据进行比对,如果一致的话就会进入应用也就是登录认证成功。

Shiro配置(重点)

引入Shiro依赖

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

配置ShiroConfig

package boc.ljh.config;

import boc.ljh.config.shiro.realm.UserRealm;
import boc.ljh.pojo.User;
import org.apache.logging.log4j.message.StringFormattedMessage;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
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;

@Configuration
public class ShiroConfig {

    //1.创建ShiroFilter 负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //给ShiroFilter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //配置系统受限和认证资源
        Map<String,String> map = new HashMap<String,String>();
        map.put("/user/addUser","authc");//authc 请求这个资源需要认证和授权
        map.put("/user/loadAllUserList","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        //配置认证界面  当需要进行认证时会跳到下面的login.jsp页面。
        shiroFilterFactoryBean.setLoginUrl("/WEB_INF/jsp/login.jsp");
        return shiroFilterFactoryBean;
    }

    //2.创建安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //给安全管理器设置Realm
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    //3.创建Realm
    @Bean
    public Realm getRealm(){
        UserRealm userRealm = new UserRealm();
        //修改凭证匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法为MD5
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        //设置散列次数
        hashedCredentialsMatcher.setHashIterations(1024);
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return userRealm;
    }
}

创建自定义的Realm

package boc.ljh.config.shiro.realm;

import boc.ljh.pojo.User;
import boc.ljh.service.UserService;
import boc.ljh.utils.ApplicationContextUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.ObjectUtils;

//自动以Realm
public class UserRealm  extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //根据身份信息
        String principal = (String) authenticationToken.getPrincipal();
        //在工厂中获取bean对象
        UserService userService = (UserService) ApplicationContextUtils.getBean("userServiceImpl");
        User user = userService.loadUserInfoByUsername(principal);
        if(!ObjectUtils.isEmpty(user)){
            return new SimpleAuthenticationInfo(user.getUserName(),user.getUserPassword(), ByteSource.Util.bytes(user.getUserSalt()),this.getName());
        }
        return null;
    }
}

生成随机盐配置

package boc.ljh.utils;

import java.util.Random;

public class SaltUtils {

    //生成随机盐
    public static String getSalt(int num){
        char[] chars = "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz!@#$%^&*()_+-={}[],./;:\"'\\".toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i <num ; i++){
            char aChar  = chars[new Random().nextInt(chars.length)];
            stringBuilder.append(aChar);
        }
        return stringBuilder.toString();
    }
}

获取工厂中bean的配置

package boc.ljh.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 配置获取工厂中bean对象
 */
@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    //根据bean名字获取工厂中指定的bean对象
    public static Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

实现用户注册功能(注册时对密码进行MD5+salt+hash散列加密)

controller

package boc.ljh.controller;

import boc.ljh.config.AppCode;
import boc.ljh.config.PaginationHelper;
import boc.ljh.config.Result;
import boc.ljh.pojo.User;
import boc.ljh.service.UserService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.jws.soap.SOAPBinding;


@Api(tags = "用户管理")
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;


    @ApiOperation("用户注册")
    @PostMapping("/register")
    @ApiOperationSupport(ignoreParameters = {
            "userId",
            "userAge",
            "userSalt"
    })
    public Result register(@RequestBody User user){
        Result result = new Result();
        Integer num = userService.registerUserInfo(user);
        if(num == 1){
            result.setMessage("注册成功");
            result.setStatus(200);
        }else{
            result.setMessage("注册失败");
            result.setStatus(500);
        }
        return result;
    }
  
}

dao

//用户注册
    Integer registerUserInfo(User user);

mapper.xml

<insert id="registerUserInfo" parameterType="boc.ljh.pojo.User">
        insert into user(user_name, user_password,user_salt) values (#{userName},#{userPassword},#{userSalt});
    </insert>

service

//用户注册
    Integer registerUserInfo(User user);

serviceImpl

@Override
    public Integer registerUserInfo(User user) {
        //1.生成随机盐
        String salt = SaltUtils.getSalt(8);
        //2.将随机盐保存到数据库
        user.setUserSalt(salt);
        //明文密码进行MD5+随机盐+hash散列处理
        Md5Hash md5Hash = new Md5Hash(user.getUserPassword(),salt,1024);
        user.setUserPassword(md5Hash.toHex());
        Integer num = userDao.registerUserInfo(user);
        return num;
    }

实现用户登录功能

controller

@ApiOperation("用户登录")
    @PostMapping("/login")
    @ApiOperationSupport(ignoreParameters = {
            "userAge",
            "userId",
            "userSalt"

    })
    public Result login(@RequestBody User user){
        Result result = new Result();
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(user.getUserName(),user.getUserPassword()));
            result.setMessage(AppCode.LOGIN_SUCCESS.message);
            result.setStatus(AppCode.LOGIN_SUCCESS.code);
            return result;
        }catch (UnsupportedOperationException e) {
            result.setMessage(AppCode.LOGIN_NAME_FALL.message);
            result.setStatus(AppCode.LOGIN_NAME_FALL.code);
            return result;
        }catch (IncorrectCredentialsException e){
            result.setMessage(AppCode.LOGIN_PASS_FALL.message);
            result.setStatus(AppCode.LOGIN_PASS_FALL.code);
            return result;
        }
    }

dao

//根据用户名获取用户信息
    User loadUserInfoByUsername(String usename);

mapper.xml

    <select id="loadUserInfoByUsername" resultMap="BaseResultMap">

service

//根据用户名获取用户信息
    User loadUserInfoByUsername(String usename);

serviceImpl

@Override
    public User loadUserInfoByUsername(String usename) {
        return userDao.loadUserInfoByUsername(usename);
    }

实现用户退出功能

controller

@ApiOperation("用户退出")
    @PostMapping("/loginout")
    public Result loginout(){
        Result result = new Result();
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        result.setStatus(200);
        result.setMessage("退出成功");
        return result;
    }
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想养一只!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值