apache shiro实现用户登录功能
配置shiro的Filter实现URL级别权限控制
配置web.xml
<!-- shiro的过滤器 -->
<filter>
<!-- 应用配置后将会去spring的配置文件中寻找与shiroFilter同名的bean -->
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置applicationContext-shiro.xml,并在applicationContext.xml中引入applicationContext-shiro.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- 配置Shiro核心Filter -->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 未认证,跳转到哪个页面 -->
<property name="loginUrl" value="/login.html" />
<!-- 登录页面页面 -->
<property name="successUrl" value="/index.html" />
<!-- 认证后,没有权限跳转页面 -->
<property name="unauthorizedUrl" value="/unauthorized.html" />
<!-- shiro URL控制过滤器规则 -->
<property name="filterChainDefinitions">
<value>
/login.html* = anon
/user_login.action* = anon
/validatecode.jsp* = anon
/css/** = anon
/js/** = anon
/images/** = anon
/services/** = anon
/pages/base/courier.html* = perms[courier:list]
/pages/base/area.html* = roles[base]
/** = authc
</value>
</property>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
<!-- 配置Realm -->
<bean id="bosRealm" class="cn.niwotaxuexiba.bos.realm.BosRealm">
<!-- 缓存区的名字 就是 ehcache.xml 自定义 cache的name -->
<property name="authorizationCacheName" value="bos" />
</bean>
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 开启shiro注解模式 -->
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" >
<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
</beans>
在applicationContext.xml中引入applicationContext-shiro.xml
<!-- 引入shiro的配置 -->
<import resource="applicationContext-shiro.xml"/>
前端页面代码编写
设置form表单的action
<form class="form-horizontal" id="loginform" name="loginform" method="post" action="user_login.action>
...
</form>
点击立即登录按钮,提交form表单
<a href="javascript:$('#loginform').submit();" class="btn btn-danger" target="_blank">
立即登录
</a>
后台Java代码实现
编写UserAction,提供login登录方法
@Namespace("/")
@ParentPackage("json-default")
@Controller
@Scope("prototype")
public class UserAction extends BaseAction<User> {
@Action(value = "user_login", results = {
@Result(name = "login", type = "redirect", location = "login.html"),
@Result(name = "success", type = "redirect", location = "index.html") })
public String login() {
// 用户名和密码 都保存在model中
// 基于shiro实现登录
Subject subject = SecurityUtils.getSubject();
// 用户名和密码信息
AuthenticationToken token = new UsernamePasswordToken(
model.getUsername(), model.getPassword());
try {
subject.login(token);
// 登录成功
// 将用户信息 保存到 Session
return SUCCESS;
} catch (AuthenticationException e) {
// 登录失败
e.printStackTrace();
return LOGIN;
}
}
}
shiro的执行流程是:应用程序–>Subject–>SecurityManager–>Realm–>安全数据
自定义Realm对象,实现认证方法。自定义的Realm接口需要集成AuthorizingRealm接口。
//自定义的Realm,实现 安全数据的连接
@Service("bosRealm")
public class BosRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
//授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("shiro 授权管理...");
return null;
}
@Override
// 认证...
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("shiro 认证管理... ");
// 转换token
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 根据用户名 查询 用户信息
User user = userService.findByUsername(usernamePasswordToken
.getUsername());
if (user == null) {
// 用户名不存在
// 参数一: 期望登录后,保存在Subject中信息
// 参数二: 如果返回为null 说明用户不存在,报用户名
// 参数三 :realm名称
return null;
} else {
// 用户名存在
// 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
// 如果密码一致 登录成功, 如果密码不一致 报密码错误异常
return new SimpleAuthenticationInfo(user, user.getPassword(),
getName());
}
}
}
将自定义的Realm注入到安全管理器SecurityManager中。
<!-- 安全管理器 -->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
service代码
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
dao代码
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
在shiroFilter中将user_login.action放行
<!-- shiro URL控制过滤器规则 -->
<property name="filterChainDefinitions">
<value>
/login.html* = anon
/user_login.action* = anon<!-- 放行 -->
/validatecode.jsp* = anon
/css/** = anon
/js/** = anon
/images/** = anon
/services/** = anon
/pages/base/courier.html* = perms[courier:list]
/pages/base/area.html* = roles[base]
/** = authc
</value>
</property>