添加 shiro依赖
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
首先写 自定义Realm
public class UserRealm extends AuthorizingRealm {
@Autowired(required = false)
private SysUserService sysUserService;
@Autowired(required = false)
SysUserRoleMapper sysUserRoleMapper;
// AuthorizationInfo代表了角色的权限信息集合 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
// 授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject();
// 获取当前user
SysUser user = (SysUser) subject.getPrincipal();
//
Map<String,Object> map = new HashMap<>();
map.put("userId",user.getId());
List<SysRole> userRoleList = sysUserRoleMapper.selRoleByuserId(map);
Set<String> permissionCode = new HashSet<>();
Set<String> roleName = new HashSet<>();
for (SysRole userRole : userRoleList) {
roleName.add(userRole.getRoleName());
}
// 将 角色名称级权限的名称放进 info中 以供 shiroConfig 拦截
info.setRoles(roleName);
return info;
}
/**
* 用户信息的认证
*
* 该方法主要执行以下操作:
* 1、检查提交的进行认证的令牌信息
* 2、根据令牌信息从数据源(通常为数据库)中获取用户信息
* 3、对用户信息进行匹配验证。
* 4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
* 5、验证失败则抛出AuthenticationException异常信息。
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=>认证 doGetAuthorizationInfo");
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
String username = userToken.getUsername();
SysUser user = sysUserService.getUserByName(username);
if (user == null){
return null;
}
String paw1 = String.valueOf(userToken.getPassword());
String paw2 = RSAUtil.privateKeyEncryption(paw1);
String paw3 = DigestUtil.md5Hex(paw2);
userToken.setPassword(paw3.toCharArray());
// 密码认证
return new SimpleAuthenticationInfo(user, user.getPassword(),this.getName());
}
}
解读代码
继承 AuthorizingRealm 需要重写 两个方法,一个是 用户认证的方法,一个是 给用户 授权的方法
1、用户认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=>认证 doGetAuthorizationInfo");
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
String username = userToken.getUsername();
SysUser user = sysUserService.getUserByName(username);
if (user == null){
return null;
}
// 用户输入的密码
String paw1 = String.valueOf(userToken.getPassword());
// 因为数据库存的是 MD5,多以对密码进行加密
String paw3 = DigestUtil.md5Hex(paw2);
userToken.setPassword(paw3.toCharArray());
// 密码认证
return new SimpleAuthenticationInfo(user, user.getPassword(),this.getName());
}
通过 userToken 中的用户名 查询用户信息 检验用户密码等 判断用户信息是否正确。
2、将用户的权限角色信息 写进info
// AuthorizationInfo代表了角色的权限信息集合 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
// 授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject();
// 获取当前user
SysUser user = (SysUser) subject.getPrincipal();
//
Map<String,Object> map = new HashMap<>();
map.put("userId",user.getId());
List<SysRole> userRoleList = sysUserRoleMapper.selRoleByuserId(map);
// 这个放 用户权限的CODE
Set<String> permissionCode = new HashSet<>();
// 这个放用户角色的名字
Set<String> roleName = new HashSet<>();
for (SysRole userRole : userRoleList) {
roleName.add(userRole.getRoleName());
}
// 将 角色名称级权限的名称放进 info中 以供 shiroConfig 拦截
info.setRoles(roleName);
return info;
}
3、在登陆的接口 需要加上这个,返回信息
@GetMapping("/login")
public String login(String username,String password,Model model){
// 获取 一个用户
Subject subject = SecurityUtils.getSubject();
// 封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 执行登录的方法 无异常就ok了
try{
subject.login(token);
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e) {//密码不存在
model.addAttribute("msg","密码错误");
return "login";
}catch (LockedAccountException e){
model.addAttribute("msg","账户被锁定");
System.out.print("账户被锁定:"+e.getMessage());
return "login";
}
// 当前用户信息被保存进Session
return "index";
// 登录成功 将当前用户保存在session中
}
shiro 配置
@Configuration
public class ShiroConfig {
// 1、创建realm对象 需要自定义类
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
/**
* @Qualifier 我们可以消除需要注入哪个 bean 的问题
* @param userRealm
* @return
*/
// 2、DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
认证过滤器:
anon:无需认证即可访问,游客身份。
authc:必须认证(登录)才能访问。
authcBasic:需要通过 httpBasic 认证。
user:不一定已通过认证,只要是曾经被 Shiro 记住过登录状态的用户就可以正常发起请求,比如 rememberMe。
授权过滤器:
perms:必须拥有对某个资源的访问权限(授权)才能访问。
role:必须拥有某个角色权限才能访问。
port:请求的端口必须为指定值才可以访问。
rest:请求必须是 RESTful,method 为 post、get、delete、put。
ssl:必须是安全的 URL 请求,协议为 HTTPS。
Filter Chain 定义说明:
1、一个URL可以配置多个 Filter,使用逗号分隔
2、当设置多个过滤器时,全部验证通过,才视为通过
3、部分过滤器可指定参数,如 perms,roles
*
* bean.setLoginUrl: 请求被拦截 跳转拦截成功页面
* setSuccessUrl:授权成功 跳转 通过的页面
* setUnauthorizedUrl:授权失败 跳转 失败的页面
*
* @param defaultWebSecurityManager
* @return
*/
// 3、shiroFilterFactoryBean 拦截
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
// 拦截器
Map<String,String> filterMap = new HashMap<>();
filterMap.put("/api/project/deleteProject","roles[administrator]");
bean.setFilterChainDefinitionMap(filterMap);
return bean;
}
}
解读代码
1、创建realm 对象
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
2、
// 2、DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
认证过滤器:
anon:无需认证即可访问,游客身份。
authc:必须认证(登录)才能访问。
authcBasic:需要通过 httpBasic 认证。
user:不一定已通过认证,只要是曾经被 Shiro 记住过登录状态的用户就可以正常发起请求,比如 rememberMe。
授权过滤器:
perms:必须拥有对某个资源的访问权限(授权)才能访问。
role:必须拥有某个角色权限才能访问。
port:请求的端口必须为指定值才可以访问。
rest:请求必须是 RESTful,method 为 post、get、delete、put。
ssl:必须是安全的 URL 请求,协议为 HTTPS。
Filter Chain 定义说明:
1、一个URL可以配置多个 Filter,使用逗号分隔
2、当设置多个过滤器时,全部验证通过,才视为通过
3、部分过滤器可指定参数,如 perms,roles
*
* bean.setLoginUrl: 请求被拦截 跳转拦截成功页面
* setSuccessUrl:授权成功 跳转 通过的页面
* setUnauthorizedUrl:授权失败 跳转 失败的页面
*
* @param defaultWebSecurityManager
* @return
*/
// 3、shiroFilterFactoryBean 拦截
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
// 拦截器
Map<String,String> filterMap = new HashMap<>();
filterMap.put("/api/project/deleteProject","roles[administrator]");
bean.setFilterChainDefinitionMap(filterMap);
return bean;
}
此处配置的 拦截器 在 删除项目的接口 用户的角色需要是 administrator,否则会报401 无权限异常。用户角色在 Realm中 放进了 info 当然这个也可以 根据权限 来拦截请求