shiro登录认证 与授权
shiro配置文件
<!-- 以下都是Apache安全框架Shiro的配置 -->
<!-- 数据库保存的密码是使用MD5算法加密的,所以这里需要配置一个密码匹配对象 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.Md5CredentialsMatcher"></bean>
<!-- 缓存管理 ,第一次 会去数据库中取权限,后面就从缓存中取 -->
<bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean>
<!-- 自定义realm -->
<bean id="customRealm" class="com.ecenter.sso.security.CustomRealm">
<!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!-- Shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
<property name="sessionManager" ref="sessionManager"/>
</bean>
<aop:config proxy-target-class="true"></aop:config>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--Shiro的核心安全接口,这个属性是必须的-->
<property name="securityManager" ref="securityManager"></property>
<!--要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面-->
<property name="loginUrl" value="/login"></property>
<!--登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码)-->
<!--<property name="successUrl" value="/"></property>-->
<!--用户访问未对其授权的资源时,所显示的连接-->
<property name="unauthorizedUrl" value="/noPower.jsp"></property>
<property name="filterChainDefinitions">
<value>
/checkCode/getCodeImage=anon
/login=anon
/userInfo/edit=anon
/userInfo/password=anon
/userInfo/passwordChange=anon
/doLogin=anon
/lib/**=anon
/**=authc
</value>
</property>
</bean>
前端登录请求
$.ajax({ type : "POST", url : "/doLogin", data : $('#form').serialize(), error : function(request) { alert("操作失败!"); }, success : function(data) { if (data == '200') { if ($('#remember-password').attr('checked')) { var cookie = new rememberPassword(); cookie.cookieRemeber(); } window.location.href = "/index"; } else if (data == '500') { $('#password').val(''); $('#checkCode').val(''); $('#checkCode').attr('placeholder',''); changeImg(); $('#password').attr('placeholder','用户名或密码不正确'); $('#password').focus(); } else if (data == '401') { $('#checkCode').val(''); $('#checkCode').attr('placeholder','验证码不正确'); changeImg(); }else if(data == '501'){ layui.use(['laypage', 'layer'], function(){ var laypage = layui.laypage ,layer = layui.layer; layer.open({ type: 2, //类型,解析url closeBtn: 1, //关闭按钮是否显示 1显示0不显示 title: '密码修改', //页面标题 shadeClose: true, //点击遮罩区域是否关闭页面 shade: 0.3, //遮罩透明度 area: ['650px', '300px'], //弹出层页面比例 content: '/userInfo/password' //弹出层的url }); }); }else { if(data == '10'){ $('#username').val(''); $('#checkCode').val(''); $('#password').val(''); $('#username').attr('placeholder','用户已删除,无法登陆'); }else if(data == '11'){ $('#username').val(''); $('#checkCode').val(''); $('#password').val(''); $('#username').attr('placeholder','用户暂未通过审核'); }else if(data == '12'){ $('#username').val(''); $('#checkCode').val(''); $('#password').val(''); $('#username').attr('placeholder','用户未能通过审核'); }else if(data == '14'){ $('#username').val(''); $('#checkCode').val(''); $('#password').val(''); $('#username').attr('placeholder','用户已被禁用'); }else if(data == '3'){ $('#username').val(''); $('#checkCode').val(''); $('#password').val(''); $('#username').attr('placeholder','用户已被禁用'); } } } });
后端登录接口 /dologin
@RequestMapping("/doLogin")
@ResponseBody
public String doLogin(HttpServletRequest request,
HttpServletResponse response,
@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("checkCode") String checkCode) {
if (!checkCode.equalsIgnoreCase((String) request.getSession().getAttribute("code"))) {
return Constant.RES_CHECKCODE_ERROR; // 验证码不正确
}
UsernamePasswordToken token = new UsernamePasswordToken(username,password, true);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
List<Session> loginedList = getLoginedSession(subject);
for (Session session : loginedList) {
session.stop();
}
Session session = subject.getSession();
if (subject.isAuthenticated()) {
Map<String, Object> claims = new HashMap<String, Object>();
User user = iUserService.findByUsername(username);
claims.put("username", username);
claims.put("usertype", user.getUsertype());
claims.put("areaCode", user.getAreacode());
if("123456".equals(password)){
session.setAttribute("username", username);
return Constant.PASSWORD_EASY;//密码太简单
}
// 验证成功后 使用JWT生成加密的token
String JWT = JavaWebToken.createJavaWebToken(claims);
session.setAttribute("Authorization", JWT);
session.setAttribute("areaCode", user.getAreacode());
session.setAttribute("usersession", user);
return Constant.RES_SUCCESS;
} else {
return Constant.RES_FAIL;
}
} catch (IncorrectCredentialsException e) {// 登录密码错误
return Constant.RES_FAIL;
} catch (ExcessiveAttemptsException e) { // 登录失败次数过多
return Constant.RES_FAIL;
} catch (UnknownAccountException e) { // 帐号不存在
return Constant.RES_FAIL;
}
}
subject.login(token);源码追踪
![]()







自定义的 Realm 对象
package com.ecenter.sso.security; public class CustomRealm extends AuthorizingRealm { @Autowired private IUserService iUserService; @Autowired(required=true) private SessionDAO sessionDAO; //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // token中包含用户输入的用户名和密码 // 第一步从token中取出用户名 String userName = (String) token.getPrincipal(); // 第二步:根据用户输入的userCode从数据库查询 User user = iUserService.findByUsername((String) token.getPrincipal()); // 如果查询不到返回null if (user == null) {// return null; } // 获取数据库中的密码 String password = user.getPassword(); //认证的用户,正确的密码 AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(userName, password, this.getName()); Session currentSession = null; Collection<Session> sessions = sessionDAO.getActiveSessions(); /* for(Session session:sessions){ if(userName.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) { //session.setTimeout(0);//设置session立即失效,即将其踢出系统 session.stop(); break; } }*/ return authcInfo; } /** * 授权,只有成功通过<span style="font-family: Arial, Helvetica, sans-serif;"> * doGetAuthenticationInfo方法的认证后才会执行。</span> */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 从 principals获取主身份信息 // 将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型), String username = (String) principals.getPrimaryPrincipal(); // 根据身份信息获取权限信息 // 从数据库获取到权限数据 // 单独定一个集合对象 ArrayList<String> permissions = (ArrayList<String>) iUserService.getUserPermission(username); // 查到权限数据,返回授权信息(要包括 上边的permissions) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 将上边查询到授权信息填充到simpleAuthorizationInfo对象中 simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; } // 清除缓存 public void clearCached() { PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals(); super.clearCache(principals); } }

浙公网安备 33010602011771号