Shiro的使用之认证拦截
Shiro是一个安全开发框架,它把系统的安全认证等相关功能抽取出来,降低了系统的开发成本。
一 Shiro实现认证拦截
步骤: 1 系统调用subject的login方法将用户信息传递给securityManager
2 securityManager将认证操作委托给Authenticator
3 Authenticator将用户输入的身份信息发送给Realm
4 Realm访问数据库获取用户信息并将信息封装并返回
5 Authenticator对封装的信息进行身份认证
输入用户信息后登陆到系统界面
1.需要的依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
2. Shiro的核心配置对象
在springboot中没有为我们自动配置shiro,所以要手动配置
- 首先创建一个配置类:SpringShiroConfig类;
- 然后在配置类中添加SecurityManager接口对象;
- 在配置类中添加一个ShiroFilterFactoryBean对象;通过此对象实现对匿名访问和认证访问
- 代码如下:
package com.py.pj.common.config;
import java.util.LinkedHashMap;
import org.apache.shiro.mgt.SecurityManager;
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;
/**
* @author WL
* @version 创建时间:2020-9-19 13:24:57
* @Description Shiro的核心配置对象
* @Configuration 此注解描述的类是一个配置对象,此对象会交给spring处理
* @Bean 此注解描述的类会被交给spring处理,由spring为我们创建对象
*/
@Configuration
public class SpringShiroConfig {
@Bean
public SecurityManager securityManager(Realm realm) {
DefaultWebSecurityManager dsm = new DefaultWebSecurityManager();
dsm.setRealm(realm);
return dsm;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean sffBean = new ShiroFilterFactoryBean();
sffBean.setSecurityManager(securityManager);
// 设置登录界面url
sffBean.setLoginUrl("/doLogin");
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("/bower_components/**", "anon");
map.put("/modules/**", "anon");
map.put("/dist/**", "anon");
map.put("/plugins/**", "anon");
// 用户登录界面允许匿名访问
map.put("/user/doLogin", "anon");
// 退出登陆
map.put("/doLogout", "logout");
// 除了静态资源,其他的都要认证
map.put("/**", "authc");
sffBean.setFilterChainDefinitionMap(map);
return sffBean;
}
}
3.业务模块实现
本模块的业务在realm模块中实现
- 3.1 根据用户名搜索用户信息
在SysUserMapper中创建findUserByUsername(String username)方法
SysUser findUserByUsername(String username);
mapper映射文件中
<select id="findUserByUsername" resultType="com.py.pj.sys.entity.SysUser">
select * from sys_users where username=#{username}
</select>
- 3.2 创建realm业务层
package com.py.pj.sys.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.py.pj.sys.dao.SysUserMapper;
import com.py.pj.sys.entity.SysUser;
/**
* @author WL
* @version 创建时间:2020-9-19 14:15:12
* @Description 授权realm继承认证,所以包含认证和授权功能
*/
@Service
public class ShiroUserRealm extends AuthorizingRealm {
@Autowired
private SysUserMapper sysUserMapper;
/**
* 设置凭证匹配器匹配规则
*/
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
// 创建凭证匹配器对象
HashedCredentialsMatcher hcm = new HashedCredentialsMatcher();
// 设置加密算法,与用户密码加密算法保持一直
hcm.setHashAlgorithmName("MD5");
// 设置加密次数
hcm.setHashIterations(1);
super.setCredentialsMatcher(hcm);
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
/**
* 重写认证 token 是从客户端传来的用户的账号信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 1.获取用户输入的用户名
UsernamePasswordToken UToken = (UsernamePasswordToken) token;
String username = UToken.getUsername();
// 2.基于用户名查用户信息
SysUser user = sysUserMapper.findUserByUsername(username);
// 3.判断用户是否存在、是否禁用
if (user == null) {
throw new UnknownAccountException();
}
if (user.getValid() == 0) {
throw new LockedAccountException();
}
// 4.封装用户信息
// 盐值是ByteSource格式的所以要转换
ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
System.out.println(user.getPassword());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, // principal (身份)
user.getPassword(), // hashedCredentials
credentialsSalt, // credentialsSalt
getName());// realName
return info;
}
}
- 3.3 controller层
@RequestMapping("doLogin")
public JsonResult doLogin(String username,String password) {
// 每个用户都是一个subject对象
Subject subject = SecurityUtils.getSubject();
// 对用户进行封装
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
// token被传给securityManager;securityManager在传递给Authentication;Authentication再传给realm,从数据库中获取并封装用户信息
subject.login(token);
return new JsonResult("OK");
}
至此,借助Shiro完成了用户的登陆认证功能。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。