Shiro权限认证

本文详细介绍了Shiro框架的权限认证过程,包括框架搭建、登陆认证的用户名+密码验证及密码加密,以及登陆授权的实现,通过自定义Realm类和Shiro标签进行权限控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Shiro权限认证

图片上传真的很累,想看图的可以访问我的个人博客:
http://www.bestrivenlf.cn/note/getNoteList

一、框架搭建

各种依赖见SSM+Shiro搭建笔记

二、登陆认证

1、最简单的用户名+密码登陆

首先需要一个login.jsp页面用来登陆

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>标题</title>
</head>
<body>

<!--
	@Author:liufan
	@Date:2018年11月17日
	@Description:求无bug。
 -->	
 <form action="/SSM-Shiro/Test/login">
 	用户名:<input name="username" />
 	<br>
 	密码:<input name="password" />
 	<br>
 	<input type="submit" value="login"/>
 
 </form>
 
</body>
</html>

然后就是controller层写一个接收表单的handler:

package cn.bestrivenlf.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.bestrivenlf.service.SayHelloService;

@Controller
@RequestMapping("/Test")
public class TestController {
	
	@RequestMapping("/login")
	public String login(String username,String password) {
        //首先要获取到subject,通过SecurityUtils.getSubject方法。
		Subject subject = SecurityUtils.getSubject();
        //然后判断当前subject是否被认证过,如果没有则进行认证。
		System.out.println("认证开始");
		if(!subject.isAuthenticated()) {
            //认证开始后,需要将用户名和密码组装程一个token传入我们的自定义realm
			UsernamePasswordToken token = new UsernamePasswordToken(username,password);
			try {
                //调用subject的login方法将认证信息传入我们自己的realm方法进行认证
				subject.login(token);
			}catch (Exception e) {
				// TODO: handle exception
				System.out.println("fail authentication");
			}
			
		}
		return "index";
	}
}

接下来就是写我们自己的认证realm类了,需要继承AuthenticatingRealm这个类

package cn.bestrivenlf.Realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.springframework.beans.factory.annotation.Autowired;

import cn.bestrivenlf.dao.UserDao;
import cn.bestrivenlf.entity.User;


public class MyRealm extends AuthenticatingRealm {

	@Autowired
	private UserDao userdao;
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// TODO Auto-generated method stub
        //首先接收来自handler的token后需要先强转成UsernamePasswordToken
		UsernamePasswordToken upToken = (UsernamePasswordToken)token;
        //从token中获取登陆用户名
		String username = upToken.getUsername();
        //接下来应该从数据库中查找用户信息,这里模拟数据
		User user = new User();
        //模拟数据用户名的密码是123456
		user.setUsername(username);
		user.setPassword("123456");
        //这里封装用户信息交给Shiro去比对
        /**
        没错我们自己不需要比对信息,将用户提交的信息和数据库查找的信息交给Shiro。Shiro会以一种更为安全的方式进行信息的比对并返回结果。
        **/
        //封装用户身份信息,即当前username或者user实体类
		Object principal = user;
        //传入这个用户的正确密码
		String credential = user.getPassword();
        //realm的name,调用父类的getName方法即可
		String realmName = super.getName();
        //封装成一个SimpleAuthenticationInfo,将其返回给shiro即可
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credential,realmName);
		return info;
		
	}
	
}

如果仅仅是简单的登陆信息认证,到这里就结束了,当然还需要将我们的Realm进行配置,当然是配置在SercurityManager里面了:

<bean id ="securityManager" class ="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
      <property name ="realm" ref ="customRealm" />
   <!-- <property name ="cacheManager" ref ="cacheManager" /> -->
    <!--<property name ="sessionManager" ref ="sessionManager"/> -->
</bean>

<!-- realm -->
<bean id ="customRealm" class ="cn.bestrivenlf.Realm.MyRealm"/>

然后在认证链中将所有请求都更改为authc拦截器,即所有路径都要认证,当然登陆请求还是要放开的:

<bean id ="shiroFilter" class = "org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name ="securityManager" ref ="securityManager" />
<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求地址将由formAuthenticationFilter进行表单认证 -->
    <property name ="loginUrl" value ="/login.jsp"/>
    <property name ="unauthorizedUrl" value ="/error"/>
    
<!-- 过滤器链定义:从上向下顺序执行,一般将/**放在最下边 
	<property name ="filters">
		<map>
			<entry key ="authc" value-ref ="formAuthenticationFilter"/>
		</map>
	</property>-->
    <property name ="filterChainDefinitions">
        <value>
        	<!-- 对静态资源设置匿名访问 -->
        	/login.jsp=anon
        	/user/logout = logout
        	/Test/login=anon
        	/**=authc
        </value>
    </property>
</bean>

至此,简单的登陆验证就完成了。

2、密码加密验证

首先选择我们的密码加密方式,比如MD5加密,然后配置在我们的Realm上:

<bean id ="customRealm" class ="cn.bestrivenlf.Realm.MyRealm">
<property name="credentialsMatcher">
	<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <!--使用的加密算法-->
		<property name="hashAlgorithmName" value="MD5">
		</property>
        <!--加密次数-->
        <property name="hashIterations" value="1000"></property>
	</bean>
</property>
</bean>

然后realm中的代码稍作修改,加入盐值和修改构造函数即可:

	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// TODO Auto-generated method stub
		UsernamePasswordToken upToken = (UsernamePasswordToken)token;
		String username = upToken.getUsername();
		User user = new User();
		user.setUsername(username);
		user.setPassword("16fe90cb7a2c8a18faf0adcb74e92dbe");
		ByteSource salt = ByteSource.Util.bytes("shagou");
		Object principal = user;
		String credential = user.getPassword();
		String realmName = super.getName();
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credential,salt,realmName);
		return info;
		
	}

三、登陆授权

讲完认证,接下来就是授权操作。

之前认证的时候我们讲到自定义Realm要继承AuthenticatingRealm来实现它的抽象方法,授权的时候也要继承一个授权类,可是java无法多继承,所以可以直接继承AuthorzingRealm,它包含了一个授权一个认证的抽象方法。

接下来就进行授权:

其实就是多实现一个方法

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// TODO Auto-generated method stub
		User principal = (User)principals.getPrimaryPrincipal();
		String username = principal.getUsername();
		Set<String> roles = new HashSet<String>();
		if(username.equals("shagou")){
			roles.add("user");
		}else if (username.equals("admin")){
			roles.add("user");
			roles.add("admin");
		}
		return new SimpleAuthorizationInfo(roles);
	}

这里分别设置了有user和admin两个角色,对应shagou和admin两个账号,密码都是123456。

前端页面使用相应的shiro标签:

注意引入命名空间:

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>

然后使用标签:

<html>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<body>
<h2>Hello World!</h2>
<shiro:hasRole name="user"><a href="/SSM-Shiro/Test/user">user.jsp</a></shiro:hasRole>
<br>
<shiro:hasRole name="admin"><a href="/SSM-Shiro/Test/admin">admin.jsp</a></shiro:hasRole>
<a href="/SSM-Shiro/user/logout">logout</a>
</body>
</html>

至此,一个完整的授权过程就结束了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值