一 pom依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
二 Shiro配置
package com.kong.qyk8.config;
import com.kong.qyk8.modules.sys.auth2.Auth2Filter;
import com.kong.qyk8.modules.sys.auth2.Auth2Realm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public Auth2Realm myAuth2Realm() {
return new Auth2Realm();
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myAuth2Realm());
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
Map<String, Filter> filters = new LinkedHashMap<>();
filters.put("auth2", new Auth2Filter());
shiroFilter.setFilters(filters);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/swagger**/**", "anon");
filterMap.put("/v2/api-docs**", "anon");
filterMap.put("/swagger-ui.html**", "anon");
filterMap.put("/swagger-resources**/**", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("**/**", "auth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
三 自定义Realm
package com.kong.qyk8.modules.sys.auth2;
import com.kong.qyk8.common.utils.DateUtils;
import com.kong.qyk8.modules.sys.entity.SysUserEntity;
import com.kong.qyk8.modules.sys.entity.SysUserTokenEntity;
import com.kong.qyk8.modules.sys.service.ShiroService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
public class Auth2Realm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof Auth2Token;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal();
Set<String> permsSet = 自己去查询就得了,简单的抱头;
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permsSet);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String accessToken = (String) token.getPrincipal();
SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken);
if (tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {
throw new IncorrectCredentialsException("token失效,请重新登录");
}
SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId());
if (user.getStatus() == 0) {
throw new LockedAccountException("账号已被锁定,请联系管理员");
}
return new SimpleAuthenticationInfo(user, accessToken, getName());
}
}
四 自定义过滤器Auth2Filter
package com.kong.qyk8.modules.sys.auth2;
import com.google.gson.Gson;
import com.kong.qyk8.common.utils.HttpContextUtils;
import com.kong.qyk8.common.utils.R;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Auth2Filter extends AuthenticatingFilter {
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
System.out.println("auth2过滤器createToken");
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
return null;
}
return new Auth2Token(token);
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
System.out.println("auth2过滤器 isAccessAllowed");
if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
return true;
}
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
System.out.println("auth2过滤器 onAccessDenied");
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));
httpResponse.getWriter().print(json);
return false;
}
return executeLogin(request, response);
}
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
System.out.println("auth2过滤器 onLoginFailure");
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
try {
Throwable throwable = e.getCause() == null ? e : e.getCause();
R r = R.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage());
String json = new Gson().toJson(r);
httpResponse.getWriter().print(json);
} catch (IOException e1) {
}
return false;
}
private String getRequestToken(HttpServletRequest httpRequest) {
String token = httpRequest.getHeader("token");
System.out.println("auth2过滤器-----从header中获取token= " + token);
if (StringUtils.isBlank(token)) {
token = httpRequest.getParameter("token");
}
return token;
}
}
五 Auth2Token
package com.kong.qyk8.modules.sys.auth2;
import org.apache.shiro.authc.AuthenticationToken;
public class Auth2Token implements AuthenticationToken {
private String token;
public Auth2Token() {
}
public Auth2Token(String token) {
this.token = token;
}
@Override
public String getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
六 登录接口
@Override
public Map<String, Object> login(SysLoginForm form) {
boolean captcha = sysCaptchaService.validate(form.getUuid(), form.getCaptcha());
if (!captcha) {
return R.error("验证码不正确");
}
SysUserEntity user = sysUserService.queryByUserName(form.getUsername());
if (user == null || !user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())) {
return R.error("账号或密码不正确");
}
if (user.getStatus() == 0) {
return R.error("账号已被锁定,请联系管理员");
}
Set<String> permissions = shiroService.getUserPermissions(user.getUserId());
R token = sysUserTokenService.createToken(user.getUserId()).put("permissions", permissions);
Subject subject = SecurityUtils.getSubject();
subject.login(new Auth2Token(token.get("token").toString()));
return token;
}