今天来记录一下Shiro的整合,完成登录校验。
1.进入jar包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
2.创建一个认证类
package com.youyou.login.config;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.youyou.login.entity.UserPO;
import com.youyou.login.service.LoginService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* 认证校验类
*
* @author: 刘朋
* <br/>date: 2019-05-05
*/
public class MyShiroRealm extends AuthorizingRealm {
//slf4j记录日志,可以不使用
private Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
@Autowired
private LoginService loginService;
/**
* 设置授权信息,目前这个方法没有什么作用
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
logger.info("开始授权(doGetAuthorizationInfo)");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//角色
Set<String> roles = new HashSet<>();
roles.add("role1");
authorizationInfo.setRoles(roles);
//权限
Set<String> permissions = new HashSet<>();
permissions.add("user:list");
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
/**
* 设置认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
logger.info("开始认证(doGetAuthenticationInfo)");
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String username = token.getUsername();
String password = new String(token.getPassword());
//查询用户是否存在,这里是用的Mybatis Plus,可以根据自己的方式进行校验
QueryWrapper<UserPO> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", username);
queryWrapper.eq("password", password);
UserPO userPO = loginService.querySingle(queryWrapper);
if (Objects.isNull(userPO)) {
throw new IncorrectCredentialsException("用户名密码错误!");
}
return new SimpleAuthenticationInfo(
userPO,
token.getPassword(),
getName()
);
}
}
3.创建shiro配置类
package com.youyou.login.config;
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.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;
@Configuration
public class ShiroConfiguration {
private static Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
/**
* 需要认证
*/
private static final String ANON = "anon";
/**
* 排除认证
*/
private static final String AUTHC = "authc";
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
logger.info("进入shiroFilter......");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置不需要拦截的路径
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//按顺序依次判断,这是一个责任链模式,如果有匹配的拦截,后面就不会匹配了
filterChainDefinitionMap.put("/static/**", ANON);
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
/************************************初始化所有的权限信息开始******************************************/
//这里,如果以后再项目中使用的话,直接从数据库中查询
filterChainDefinitionMap.put("/user/list", "authc,perms[user:list]");
//filterChainDefinitionMap.put("/user/add", "authc,perms[user:add]");
/***************************************初始化所有的权限信息开始结束*********************************************/
filterChainDefinitionMap.put("/api/**", AUTHC);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
// shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权界面
shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
//后面这里可以设置缓存的机制
return myShiroRealm;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
4.创建controller
package com.youyou.login.controller;
import com.youyou.common.http.ResponseMessage;
import com.youyou.common.http.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* 登录接口
*
* @author 刘朋
* <br/>date 2019-03-12
*/
@Api(description = "登录接口")
@RestController
@RequestMapping("")
public class LoginController {
private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
@ApiOperation(value = "登录")
@GetMapping("/login")
public ResponseMessage<String> login(ServletRequest request, String username, String password) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//设置session过期时间(秒)
httpServletRequest.getSession().setMaxInactiveInterval(1800);
if (StringUtils.isAnyBlank(username, password)) {
return Result.error("用户名密码不能为空!");
}
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken();
usernamePasswordToken.setUsername(username);
usernamePasswordToken.setPassword(password.toCharArray());
try {
subject.login(usernamePasswordToken);
} catch (IncorrectCredentialsException e) {
LOGGER.error("用户名密码错误!");
return Result.error("用户名密码错误!");
}
return Result.success("登录成功!");
}
}
噢耶!完成整合!