Shiro框架入门
1、认证 登录
检验待登录的用户是否是系统合法用户,是,认证通过,不是,就拒绝
xml配置文件
<!-- MyShiroRealm bean 配置-->
<bean id="myShiroRealm" class="com.hqyj.fj.realm.MyShiroRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<!-- 配置shiro核心组件 SecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 我们自定义的认证域对象注入到SecurityManager对象中-->
<property name="realm" ref="myShiroRealm" />
</bean>
pom.xml
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
java代码
package com.hqyj.fj.realm;
import com.hqyj.fj.pojo.Role;
import com.hqyj.fj.pojo.User;
import com.hqyj.fj.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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Set;
/*
* 认证域
* 给shiro框架返回系统中用户的认证信息
* 给shiro框架返回系统中用户的授权信息
* */
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//给shiro框架返回系统中待认证用户的认证信息
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//使用认证令牌获取当前待登录的用户名
String username = (String)token.getPrincipal();
//在我们的系统中查询用户的认证信息
User user = userService.getOneByUsername(username);
//如果用户不存在,抛出用户不存在的异常
if(user == null){
throw new UnknownAccountException(username+"不存在");
}
//在shiro会话域*享用户信息,以便业务层获取使用
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute("loginUser", user);
//使用三个参数的构造方法来构造,用户名、密码、当前认证域的名称
// SimpleAuthenticationInfo info =
// new SimpleAuthenticationInfo(username, user.getPassword(), getName());
ByteSource saltBytes =ByteSource.Util.bytes(user.getUsername());
SimpleAuthenticationInfo info =
new SimpleAuthenticationInfo(username, user.getPassword(), saltBytes,getName());
System.out.println("获取认证信息");
System.out.println(info);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//是下面关于授权的代码,可以复制下面的//doGetAuthenticationInfo方法
return null;
}
}
控制层controlle java代码
@RequestMapping("/login")
@ResponseBody
public Map<String, Object> login(String username, String password){
//检查请求参数
if(username == null || password == null){
Map<String, Object> result = new HashMap<>();
result.put("code",-9);
result.put("message","请求参数错误");
return result;
}
//调用服务层实现业务
return userServie.login(username,password);
}
@RequestMapping("/logout")
@ResponseBody
public Map<String, Object> logout(){
//调用服务层实现业务
return userServie.logout();
}
服务层servrce java代码
@Override
public Map<String, Object> login(String username, String password) {
Map<String, Object> result = new HashMap<>();
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//判断当前是否已经认证过
if(!subject.isAuthenticated()){
//创建一个认证令牌
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//做登录
try{
subject.login(token);
}catch (UnknownAccountException e){
//未知账号异常
result.put("code", -1);
result.put("message",username+"用户不存在");
return result;
}catch (IncorrectCredentialsException e){
//密码错误异常
result.put("code", -2);
result.put("message",username+"用户密码错误");
return result;
}catch (AuthenticationException e){
result.put("code",-10);
result.put("message","认证失败");
return result;
}
}
//认证通过,获取已保存在shiro session域中的用户信息
Session session = subject.getSession();
Object loginUser = session.getAttribute("loginUser");
result.put("code", 0);
result.put("message",username +"认证成功");
//直接返回给控制器方法
result.put("loginUser",loginUser);
return result;
}
@Override
public Map<String, Object> logout() {
//使用shiro框架获取当前用户
Subject subject = SecurityUtils.getSubject();
//使用shiro对当前用户登出
subject.logout();
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("message", "成功登出");
return result;
}
核心代码讲解
2、授权
当已认证用户系统收收权限时,检查所具有的权限,如果有该资源的访问权限,权限通过,允许访问,反之,拒绝访问
xml代码
<!-- shiro过滤器,用于授权 -->
<!-- 这里的id shiroFilter 和web.xml中配置的代理过滤器的名称一致-->
<!-- 当已经认证的用户访问系统资源时,检查所具有的权限 如果有访问权限
授权通过,允许访问吧,反之,拒绝访问
web应用收权限-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 没有认证过的用户,访问受限资源时,shiro直接跳转该配置的url-->
<property name="loginUrl" value="/index.jsp"></property>
<!-- 已认证过但是没有访问权限的用户 访问受限资源时 shiro直接跳转到该处置的url-->
<property name="unauthorizedUrl" value="/unauthorized.jsp"></property>
<property name="filterChainDefinitions">
<value>
<!-- 配置过滤器链
想要控制url=身份信息:anon 匿名用户
authc 认证通过用户
roles[角色名]具有某个角色的用户
permes[权限名]具有某个权限的用户-->
/shiroTag=anon
/index.jsp=anon
/user/login=anon
/shiro/mustauthc=authc
/shiro/mustauthc=roles[管理员]
/shiro/mustnormal=roles[普通用户]
/**=authc
</value>
</property>
</bean>
java代码
package com.hqyj.fj.realm;
import com.hqyj.fj.pojo.Role;
import com.hqyj.fj.pojo.User;
import com.hqyj.fj.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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Set;
/*
* 认证域
* 给shiro框架返回系统中用户的认证信息
* 给shiro框架返回系统中用户的授权信息
* */
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//给shiro框架返回系统中待认证用户的认证信息
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//是上面关于认证的代码,可以复制上面的 doGetAuthenticationInfo方法;
return null;
}
//给shiro框架返回系统中的信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("获取授权信息");
String username=(String) principals.getPrimaryPrincipal();
System.out.println(username);
//获取待授权的用户权限信息:角色信息,和权限信息
User user=userService.getOneByUsername(username);
//组装一个Set<String>角色信息
Set<String> roles=new HashSet<>();
//组装一个Set<String>权限信息
Set<String> perms=new HashSet<>();
for (Role role:user.getRoles()){
roles.add(role.getName());
}
//创建一个授权角色信息
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//赋予角色权限
info.setRoles(roles);
//赋予权限相关的授权信息
info.setStringPermissions(perms);
return info;
}
}
结果
登录成功
登录失败
授权问题
3、Session
Session 可以不通过java web 的session对象来实现会话功能,可以使用shiro session对象实现会话领域的数据共享问题
4、加密
登录时的密码,加密
-
散列算法
MD5 SHA1 SHA256 明文-----》xxxxx32234af455将原文的关键字提取出来,生成一串看不懂的暗文信息,从暗文信息无法还原成原文,同一个原文信息转换成唯一一个暗文信息。
-
加密算法
可以加密解密的算法
通过算法进行密码加密
xml代码
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 这里配置的算法和迭代此地,和MD5Util是一致的-->
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value="1000"></property>
</bean>
<!-- MyShiroRealm bean 配置-->
<bean id="myShiroRealm" class="com.hqyj.fj.realm.MyShiroRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
java代码
package com.hqyj.fj.utils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
/*
* 使用shiro 提供的加密相关的工具类做个加密(散列算法)明文->暗文
* */
public class MD5Util {
/*
* password 原文
* slat 盐
* 多次使用散列算法进行加密,增加密码强度,破解难度
* 加盐:增加密码强度,破解难度
*/
public static String md5Hash(String password,String salt){
ByteSource slaBytes=ByteSource.Util.bytes(salt);
//SimpleHash(String algorithmName, Object source, Object salt)
SimpleHash simpleHash= new SimpleHash("MD5",password,slaBytes,1000);
return simpleHash.toString();
}
}
测试类结果
@Test
public void testMd5Hash(){
String password="123456";
String salt="zhangsan";
String hashePass= MD5Util.md5Hash(password,salt);
System.out.println(hashePass);
}
此时123456已经加密