目录
2.2 配置spring-shiro.xml文件(Spring与Shiro集成)
2.3 web.xml文件,添加shiroFilter的配置
3. 创建LoginController实现Shiro身份认证登录
重要:
在 shiro 中,用户需要提供principals (身份)和credentials(凭证)给shiro,从而应用能验证用户身份即帐号/密码
1. 定义实体及关系
2. 自定义Realm
Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权。通常自定义的realm继承AuthorizingRealm
注1:体系结构见“shiro提供的realm.png”
AuthorizationInfo:授权信息
AuthenticationInfo:认证信息
2.1 自定义Realm
package com.jmh.shiro.utils;
import com.jmh.shiro.model.User;
import com.jmh.shiro.service.IUserService;
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.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import javax.annotation.Resource;
import java.net.Authenticator;
public class Realm extends AuthorizingRealm {
//注入
@Resource
private IUserService iUserService;
/**
* 提供授权信息
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 提供认证信息
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//从令牌中获取用户名
String username = (String)token.getPrincipal();
//通过用户名去数据库获取用户对应信息
User user = iUserService.selectByUserName(username);
//判断用户信息不为空
if(null==user){
throw new RuntimeException("用户信息为空");
}
//设置数据库用户到SimpleAuthenticationInfo
SimpleAuthenticationInfo siml=new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
this.getName()
);
return siml;
}
}
2.2 配置spring-shiro.xml文件(Spring与Shiro集成)
- 需要改的地方已注释表明
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置自定义的Realm-->
<!--****************************** 需要修改01 ***************************************-->
<bean id="shiroRealm" class="com.jmh.shiro.utils.Realm">
<!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
<!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
<!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
<!--以下三个配置告诉shiro将如何对用户传来的明文密码进行加密-->
<property name="credentialsMatcher">
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--指定hash算法为MD5-->
<property name="hashAlgorithmName" value="md5"/>
<!--指定散列次数为1024次-->
<property name="hashIterations" value="1024"/>
<!--true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储-->
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
</property>
</bean>
<!--注册安全管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroRealm" />
</bean>
<!--Shiro核心过滤器-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager" />
<!-- 身份验证失败,跳转到登录页面 -->
<property name="loginUrl" value="/home/index.shtml"/>
<!-- 身份验证成功,跳转到指定页面 -->
<!--<property name="successUrl" value="/index.jsp"/>-->
<!-- 权限验证失败,跳转到指定页面 -->
<!--<property name="unauthorizedUrl" value="/user/noauthorizeUrl"/>-->
<!-- Shiro连接约束配置,即过滤链的定义 -->
<property name="filterChainDefinitions">
<value>
<!--
注:anon,authcBasic,auchc,user是认证过滤器
perms,roles,ssl,rest,port是授权过滤器
-->
<!--anon 表示匿名访问,不需要认证以及授权-->
<!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
<!--roles[admin]表示角色认证,必须是拥有admin角色的用户才行-->
/user/login=anon
/book/**=authc
/common/**=authc
<!-- /css/** = anon
/images/** = anon
/js/** = anon
/ = anon
/user/logout = logout
/user/** = anon
/userInfo/** = authc
/dict/** = authc
/console/** = roles[admin]
/** = anon-->
</value>
</property>
</bean>
<!-- Shiro生命周期,保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
- 同时也要将spring-shiro.xml也要导入到spring.xml文件中
<import resource="spring-shiro.xml"/>
filterChainDefinitions Shiro过滤链定义类型:
(1) anon,authcBasic,auchc,user是认证过滤器
(2) perms,roles,ssl,rest,port是授权过滤器<!--anon 表示匿名访问,不需要认证以及授权-->
<!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
<!--roles[admin]表示角色认证,必须是拥有admin角色的用户才行-->
<!--user表示用户不一定已通过认证,只要曾被Shiro记住过登录状态的用户就可以正常发起请求,比如rememberMe-->
<!--perms表示指定过滤规则,这个一般是扩展使用,不会使用原生的-->
<!--port表示请求的URL端口验证-->
<!--ssl表示安全的URL请求,协议为https-->
<!--rest表示根据请求的方法,如post、get、delete等-->
2.3 web.xml文件,添加shiroFilter的配置
<!--****************************** shiro过滤器定义 ***************************************-->
<!-- shiro过滤器定义 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.4 添加pom相关依赖
<!-- ********************** shiro相关依赖 ********************** -->
<!-- shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- 添加shiro web支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--shiro和spring的集成-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
3. 创建LoginController实现Shiro身份认证登录
package com.jmh.shiro.controller;
import com.jmh.shiro.model.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.hibernate.validator.constraints.EAN;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/login")
public class LoginController {
/**
* 点击登录跳转登录页面
*/
@RequestMapping("toLogin")
public String toLogin(){
return "login";
}
/**
* 登录验证方法
*/
@RequestMapping("/login")
public String login(User user, HttpSession httpSession){
//获取主体
Subject subject = SecurityUtils.getSubject();
//使用登录令牌
UsernamePasswordToken upt=new UsernamePasswordToken(user.getUsername(),user.getPassword());
try {
//使用主体登录
subject.login(upt);
//将用户名保存到作用域
httpSession.setAttribute("msg",user.getUsername());
}catch (RuntimeException e){
throw new RuntimeException("账号或密码错误");
}
//验证成功
return "loginIndex";
}
/**
* 点击退出
*/
@RequestMapping("/toLoginOut")
public String toLoginOut(){
//获取主体
Subject subject=SecurityUtils.getSubject();
//使用主体退出
subject.logout();
return "index";
}
}
- 前端代码
<%--
Created by IntelliJ IDEA.
User: 蒋明辉
Date: 2022/8/20
Time: 1:18
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/login/login" method="post">
账 号: <input type="text" name="username"/><br/>
密 码: <input type="password" name="password"/><br/>
<input type="submit" value="登录">
</form>
</body>
</html>