一、Shiro核心组件
shiro的运行机制
一、Shiro实现登录认证()
1.首先继承 AuthorizingRealm 类,用于实现登录和认证
分别实现两个方法
doGetAuthorizationInfo //用于授权
doGetAuthenticationInfo //用于认证
2.首先需要封装用户的信息,因为用户名和密码已经传进来了,并且封装到了方法参数AuthenticationToken 中的 authenticationToken 内部,所以要获取用户的信息,比如账号和密码,就需要获取 UsernamePasswordToken 的Token。
3.获取Token之后然后取得Token中用户的用户名,从数据库查询用户的信息并返回。拿到用户的信息之后判断用户是否存在。
4.如果数据库查询的对象不为空:验证完用户存在之后,要验证密码就需要创建 SimpleAuthenticationInfo 的对象,并把数据库查询到的用户user,用户的密码user.getPassword()和getName()传进参数位置中。最后把创建的SimpleAuthenticationInfo 对象返回。
5.SimpleAuthenticationInfo 是把传进来的用户数据,即Token获得的密码和数据库获得的密码进行对比来判断密码是否正确。
6.如果数据库查询的对象为空:则返回null。
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken= (UsernamePasswordToken) authenticationToken;
User user = userService.selectByUserName(usernamePasswordToken.getUsername());
if(user!=null){
return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
}
return null;
}
二、 Shiro配置类的配置
1. 配置安全管理器,开发者自定义的Realm需要注入进 DefaultWebSecurityManager进行管理才能生效。
2. 自定义的UserRealm
package com.realm;
import com.domain.User;
import com.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
@Component
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
Set roles=new HashSet<>();
roles.add(user.getUsername());
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
return null;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken= (UsernamePasswordToken) authenticationToken;
User user = userService.selectByUserName(usernamePasswordToken.getUsername());
if(user!=null){
return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
}
return null;
}
}
3.注入自定义的Realm
@Bean public UserRealm userRealm(){ return new UserRealm(); }
4.创建安全管理器,并将自定义的UserRealm注入管理器中
使用 @Qualifier (" userRealm ") 注释可根据名称注入方法中
@Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager manager=new DefaultWebSecurityManager(); manager.setRealm(userRealm); return manager; }
5.创建过滤器工厂
注入安全管理器 DefaultWebSecurityManager
其中的编写认证和授权规则
创建过滤器工厂ShiroFilterFactoryBean并在过滤器工厂中设置安全管理器
ShiroFilterFactoryBean factoryBean=new ShiroFilterFactoryBean(); //创建过滤器工厂 factoryBean.setSecurityManager(defaultWebSecurityManager); //设置
进行权限设置
Map map=new HashMap<>();
map.put("/student/menu","authc");
factoryBean.setFilterChainDefinitionMap(map); //设置拦截的地址和认证过滤器
factoryBean.setLoginUrl("/user/entry"); //设置允许访问的地址用来登录
最终代码
package com.config;
import com.realm.UserRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
*
* @return
*/
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
/**
*
* @param userRealm
* @return
*/
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
manager.setRealm(userRealm);
return manager;
}
/**
*authc登陆验证
* anon无需登录
* @param defaultWebSecurityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean factoryBean=new ShiroFilterFactoryBean(); //创建过滤器工厂
factoryBean.setSecurityManager(defaultWebSecurityManager); //设置
Map map=new HashMap<>();
map.put("/student/menu","authc");
factoryBean.setFilterChainDefinitionMap(map); //设置拦截的地址和认证过滤器
factoryBean.setLoginUrl("/user/entry"); //设置允许访问的地址用来登录
return factoryBean;
}
}
三、在Controller层进行配置
@RequestMapping("/login")
@ResponseBody
public R login(User user,HttpServletRequest request){
Subject subject = SecurityUtils.getSubject();//获取用户的信息
String tmppassword=user.getPassword(); //进行加密,保证密码验证成功,因为数据库存储的密码已MD5加密
tmppassword=DigestUtils.md5DigestAsHex(tmppassword.getBytes());
UsernamePasswordToken token=new UsernamePasswordToken(user.getUsername(),tmppassword);//使用用户信息创建Token令牌
try {
subject.login(token);//将生成的Token用于身份验证,跳转AuthenticationInfo认证,进行认证
User userPrincipal = (User) subject.getPrincipal();
request.getSession().setAttribute("account",user.getUsername());
return R.success("登陆成功");
} catch (UnknownAccountException e) {
e.printStackTrace();
return R.error("账号不存在");
} catch(IncorrectCredentialsException e){
e.printStackTrace();
return R.error("密码错误");
}
}
四、Shiro实现授权
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取当前用户信息
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
//设置角色
Set roles=new HashSet<>();
roles.add(user.getUsername());
//设置权限
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
return authorizationInfo;
}
总代码
package com.realm;
import com.domain.User;
import com.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
@Component
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取当前用户信息
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
//设置角色
Set roles=new HashSet<>();
roles.add(user.getUsername());
//设置权限
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
return authorizationInfo;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken= (UsernamePasswordToken) authenticationToken;
User user = userService.selectByUserName(usernamePasswordToken.getUsername());
if(user!=null){
return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
}
return null;
}
}
五、退出
Controller层创建Logout
@RequestMapping("/logout")
@ResponseBody
public R logout(){
Subject subject = SecurityUtils.getSubject();//获取用户信息
subject.logout();//取消认证和授权
return R.success("退出");
}
如果退出则调用该接口,则实现认证取消