shiro系列(四):认证

1. 获取当前的 Subject. 调用 SecurityUtils.getSubject();
2. 测试当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated() 
3. 若没有被认证, 则把用户名和密码封装为 UsernamePasswordToken 对象
1). 创建一个表单页面
2). 把请求提交到 SpringMVC 的 Handler
3). 获取用户名和密码. 
4. 执行登录: 调用 Subject 的 login(AuthenticationToken) 方法. 
5. 自定义 Realm 的方法, 从数据库中获取对应的记录, 返回给 Shiro.
1). 实际上需要继承 org.apache.shiro.realm.AuthenticatingRealm 类
2). 实现 doGetAuthenticationInfo(AuthenticationToken) 方法. 
6. 由 shiro 完成对密码的比对. 

package com.atguigu.shiro.handlers;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/shiro")
public class ShiroHandler {

	
	@RequestMapping("/login")
	public String login(@RequestParam("username")String username, 
			@RequestParam("password")String password){
        
        //获取Subkect
		Subject subject = SecurityUtils.getSubject();
		
		if(!subject.isAuthenticated()){
			//把用户名和密码封装成UsernamePasswordToken对象
			UsernamePasswordToken token = new UsernamePasswordToken(username,password);
			//记住我
			token.setRememberMe(true);
			try {
				//执行登陆
				subject.login(token);
			} catch (AuthenticationException e) {
				// TODO: handle exception
				System.out.println("登录失败:"+e.getMessage());
			}
		}
		
		return "redirect:/list.jsp";
	}
}

 

数据库中的密码是经过MD5加盐值加密1024次后的结果所以认证时,前台传过来的密码也要在shiro中进行加密。在applicationContext.xml中配置加密方法及次数

<bean id="jdbcRealm" class="com.atguigu.shiro.realms.ShiroRealm">
    	<property name="credentialsMatcher">
    		<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    			<!-- 指定加密算法为MD5 -->
    			<property name="hashAlgorithmName" value="MD5"></property>
    			<!-- 指定加密1024次 -->
    			<property name="hashIterations" value="1024"></property>
    		</bean>
    	</property> 
    </bean>

subject.login(token)之后会进入自定义的Realm的doGetAuthenticationInfo方法

package com.atguigu.shiro.realms;

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.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.util.ByteSource;

public class ShiroRealm extends AuthenticatingRealm {

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("doGetAuthenticationInfo:"+token);
		//1.把AuthenticationToken转换成UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		//2.从UsernamePasswordToken中获取username
		String username = upToken.getUsername();
		//3.调用数据库的方法,从数据库中查询username对应的用户记录
		System.out.println("从数据库中获取username:"+username + "所对应的用户信息");
		//4.若用户不存在,则可以抛出UnknownAccountException 异常
		if("unknown".equals(username)){
			throw new UnknownAccountException("用户不存在!");
		}
		//5.根据用户信息的情况,决定是否抛出其他的异常
		if("master".equals(username)){
			throw new LockedAccountException("用户被锁定");
		}
		//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
		//以下信息是从数据库中获取的.
		//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象. 
		Object principal = username;
		//2). credentials: 密码. 注册时经过MD5加上盐值username加密1024次后的字符串
		Object credentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4";
		if("admin".equals(username)){
			credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
		}else if("user".equals(username)){
			credentials = "098d2c478e9c11555ce2823231e02ec1";
		}
		//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
		String realmName = getName();
		//4).盐值 将盐值也传给shiro
		ByteSource credentialsSalt  = ByteSource.Util.bytes(username);
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
		
		return info;
	}
	

}

前台传进来的username和password封装到UsernamePasswordToken中传给shiro

从数据库中获取实体类并将username或该实体类、密码、盐值、realmname封装进SimpleAuthenticationInfo返回(传给shiro)

在shiro内部进行登录比较

用户信息可能保存在不同的数据库,加密算法也可能不同,所以需要不同的Realm,

在applicationContext.xml中添加Realm配置

<bean id="secondRealm" class="com.atguigu.shiro.realms.SecondRealm">
    	<property name="credentialsMatcher">
    		<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    			<property name="hashAlgorithmName" value="SHA1"></property>
    			<property name="hashIterations" value="1024"></property>
    		</bean>
    	</property>
    </bean>

将该secondRealm添加到SecurityManager中

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="authenticator" ref="authenticator"/>
        <property name="realms">
        	<list>
    			<ref bean="jdbcRealm"/>
    			<ref bean="secondRealm"/>
    		</list>
        </property>
    </bean>

同时配置shiro的认证策略

<bean id="authenticator" 
    	class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
    	<!-- 认证策略 
    		1.AtLeastOneSuccessfulStrategy只要一个Realm认证成功就可以
    		2.AllSuccessfullStrategy需要所有的Realm都认证成功
    	-->
    	<property name="authenticationStrategy">
    		<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
    	</property>
    </bean>

再添加一个新的继承AuthenticatingRealm的类,实现doGetAuthenticationInfo(),认证完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值