在ShiroRealm 中 对所有 引入的service 加上注解 @Lazy ,防止 事务回滚失败。具体原因看该文章
新增整合swagger2,因为之前整合了shiro,所以再访问swagger的时候总是被拦截导致无法访问,因此在ShiroConfiguration配置文件中,放开对swagger的拦截
新增CORS跨域配置。
待解决问题:前端利用vue传sessionid,后台通过shiro接收一直接收不到,后前端改成jQuery才可以,不知道问题出在哪
新增@RequiresRoles角色控制,个人感觉@RequiresRoles角色控制,属于粗粒度,@RequiresPermissions属于细粒度,因为@RequiresPermissions能给每个接口定义不同的权限
如下:
@RequiresRoles(value = “admin”)
@RequiresPermissions(“user:updateSysUser”)
两者属于and 的关系,同时添加注解,会先验证此接口是否有规定的角色,然后验证是否有该权限,必须同时满足才会通过认证
@RequiresPermissions多权限是分两种的,这里要注意
第一种:必须全部符合(默认不写或者在后面添加logical = Logical.AND)
@RequiresPermissions(value={“studentMan:find_record_list”,“teacher:find_record_list”})
上面这种情况是默认当前对象必须同时全部拥有指定权限
第二种:符合其中一个即可(logical = Logical.OR)
@RequiresPermissions(value={“studentMan:find_record_list”,“teacher:find_record_list”},logical=Logical.OR)
上面这种情况则是只要有其中一个权限即可访问
pom文件
//shiro
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.2.3</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
<!--集成swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
package rongheng.member.utils;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.Validate;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import rongheng.member.entity.SysUser;
import rongheng.member.mapper.UserMapper;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.text.DecimalFormat;
public class UserUtils {
private static UserMapper userMapper = SpringContextHolder.getBean(UserMapper.class);
private static DecimalFormat df = new DecimalFormat("############0.00");
/**
* 根据ID获取用户
* @param userid
* @return 取不到返回null
*/
public static SysUser get(String userid){
SysUser sysUser = userMapper.get(userid);
if (sysUser == null){
return null;
}
return sysUser;
}
/**
* 新的获取当前登录用户的对象
* @return
*/
public static SysUser getSysUser(){
SysUser sysUser = (SysUser) SecurityUtils.getSubject().getPrincipal();
return sysUser;
}
public static Session getSession(){
try{
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession(false);
if (session == null){
session = subject.getSession();
}
if (session != null){
return session;
}
// subject.logout();
}catch (InvalidSessionException e){
}
return null;
}
/**
* 生成安全的密码,生成随机的16位salt并经过1024次 sha-1 hash
*/
public String entryptPassword(String plainPassword) {
String plain = unescapeHtml(plainPassword);
byte[] salt = generateSalt(8);
byte[] hashPassword = sha1(plain.getBytes(), salt, 1024);
return encodeHex(salt)+encodeHex(hashPassword);
}
/**
* Hex编码.
*/
public String encodeHex(byte[] input) {
return new String(Hex.encodeHex(input));
}
/**
* Html 解码.
*/
public String unescapeHtml(String htmlEscaped) {
return StringEscapeUtils.unescapeHtml4(htmlEscaped);
}
/**
* 生成随机的Byte[]作为salt.
*
* @param numBytes byte数组的大小
*/
public byte[] generateSalt(int numBytes) {
SecureRandom random = new SecureRandom();
Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", numBytes);
byte[] bytes = new byte[numBytes];
random.nextBytes(bytes);
return bytes;
}
public byte[] sha1(byte[] input, byte[] salt, int iterations) {
return digest(input,"SHA-1", salt, iterations);
}
/**
* 对字符串进行散列, 支持md5与sha1算法.
*/
private byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
if (salt != null) {
digest.update(salt);
}
byte[] result = digest.digest(input);
for (int i = 1; i < iterations; i++) {
digest.reset();
result = digest.digest(result);
}
return result;
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
//double四舍五入保留两位小数 返回字符串
public static String doubleBackTwoString(double number){
return df.format(number);
}
//double四舍五入保留两位小数 0.01是double类型的 又会变长
public static double doubleBackTwo(double number){
return Double.parseDouble(df.format(number));
}
}
主要目的通过sessionid验证用户的登录状态
package rongheng.member.session;
import java.io.Serializable;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
/**
* 自定义WEB会话管理类
*/
public class SessionManager extends DefaultWebSessionManager {
public SessionManager() {
super();
}
@Override
public Serializable getSessionId(SessionKey key) {
Serializable sessionId = key.getSessionId();
if(sessionId == null){
HttpServletRequest request = WebUtils.getHttpRequest(key);
HttpServletResponse response = WebUtils.getHttpResponse(key);
sessionId = this.getSessionId(request,response);
}
HttpServletRequest request = WebUtils.getHttpRequest(key);
request.setAttribute("sessionid",sessionId ==null?"":sessionId.toString());
return sessionId;
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String sid = request.getParameter("sessionid");
// String sid = WebUtils.toHttp(request).getHeader("sessionid");
if (StringUtils.isNotBlank(sid)) {
// 设置当前session状态
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session来源与url
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return sid;
}else{
Serializable sessionId = super.getSessionId(request, response);
return sessionId;
}
}
@Override
protected Session retrieveSession(SessionKey sessionKey) {
try{
return super.retrieveSession(sessionKey);
}catch (UnknownSessionException e) {
// 获取不到SESSION不抛出异常
return null;
}
}
}
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.filter.DelegatingFilterProxy;
import rongheng.member.realm.FormAuthenticationFilter;
import rongheng.member.realm.ShiroRealm;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfiguration {
//将自己的验证方式加入容器
@Bean
public ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
return shiroRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setSessionManager(sessionManager());
return securityManager;
}
@Bean
public SessionManager sessionManager(){
return new rongheng.member.session.SessionManager();
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//默认跳转到登陆
shiroFilterFactoryBean.setLoginUrl("/main/login");
//自定义过滤器
Map<String, Filter> filterMap=new LinkedHashMap<>();
//此处是被拦截的接口所需要访问的类,这里是自己去重新定义的
FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
shiroFilterFactoryBean.setFilters(filterMap);
filterMap.put("authc",formAuthenticationFilter);
Map<String,String> filterChainDefinitionMap=new LinkedHashMap<>();
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/loginOut", "logout");
//authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
//main 是指controller层的接口
filterChainDefinitionMap.put("/main/**","anon");
/*放开对swagger的拦截*/
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger/**", "anon");
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/configuration/**", "anon");
//其他所有接口都需要认证,也就是需要之前输入过账号密码登录过
//过滤链定义,从上向下顺序执行,一般将/**放在最为下边
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Shiro生命周期处理器
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
/**
* 自动创建代理
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
//对应web.xml中对应的shiro过滤
@Bean
public FilterRegistrationBean delegatingFilterProxy(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
}
/**
* 用户和密码(包含验证码)令牌类
*/
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
private static final long serialVersionUID = 1L;
private String captcha;
private boolean mobileLogin;
private String sessionid;
public UsernamePasswordToken() {
super();
}
public UsernamePasswordToken(String username, char[] password,
boolean rememberMe, String host, String captcha, boolean mobileLogin) {
super(username, password, rememberMe, host);
this.captcha = captcha;
this.mobileLogin = mobileLogin;
}
public UsernamePasswordToken(String username,String password, String sessionid){
super(username,password);
this.sessionid = sessionid;
}
public String getCaptcha() {
return captcha;
}
public void setCaptcha(String captcha) {
this.captcha = captcha;
}
public String getSessionid() {
return sessionid;
}
public void setSessionid(String sessionid) {
this.sessionid = sessionid;
}
public boolean isMobileLogin() {
return mobileLogin;
}
}
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import rongheng.member.entity.ResponseState;
import rongheng.member.utils.StringUtils;
/**
* 表单验证(包含验证码)过滤类
* @author ThinkGem
* @version 2014-5-19
*/
@Service
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";
public static final String DEFAULT_MOBILE_PARAM = "mobileLogin";
public static final String DEFAULT_MESSAGE_PARAM = "message";
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
private String mobileLoginParam = DEFAULT_MOBILE_PARAM;
private String messageParam = DEFAULT_MESSAGE_PARAM;
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
if (password==null){
password = "";
}
boolean rememberMe = isRememberMe(request);
String host = StringUtils.getRemoteAddr((HttpServletRequest)request);
String captcha = getCaptcha(request);
boolean mobile = isMobileLogin(request);
return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha, mobile);
}
@Override
public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (this.isLoginRequest(request, response)) {
//createToken(request,response); 这个写在了登录里面
return true;
} else {
//实现CORS跨域配置
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin,Content-Type,Accept,Authentication-Token,X-Requested-With");
ResponseState responseState = new ResponseState();
responseState.setState("403");
responseState.setMsg("用户未登录");
httpServletResponse.getWriter().write(JSON.toJSONString(responseState));
return false;
}
}
public String getCaptchaParam() {
return captchaParam;
}
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
}
public String getMobileLoginParam() {
return mobileLoginParam;
}
protected boolean isMobileLogin(ServletRequest request) {
return WebUtils.isTrue(request, getMobileLoginParam());
}
public String getMessageParam() {
return messageParam;
}
}
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
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.credential.HashedCredentialsMatcher;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import rongheng.member.entity.SysUser;
import rongheng.member.service.pc.UserService;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
public class ShiroRealm extends AuthorizingRealm {
@Autowired
@Lazy
private UserService userService;
@Override
public String getName() {
return "ShiroRealm";
}
//权限认证
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户
SysUser sysUser = (SysUser) SecurityUtils.getSubject().getPrincipal();
List<String> permissions = new ArrayList<String>();
List<String> roles = new ArrayList<>();
//授予所有权限
if (sysUser.getUsername().equals("admin")){
permissions.add("*:*");
roles = userService.getRoles(sysUser.getUserid());
}else {
//查询当前用户所拥有的所有权限
permissions = userService.getPermission(sysUser.getUserid());
//查询当前用户所拥有的所有角色
roles = userService.getRoles(sysUser.getUserid());
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissions);
info.addRoles(roles);
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//通过username 和sessionid 登录
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username=(String) token.getUsername();
SysUser sysUser = userService.getUserByUsername(username);
if (sysUser == null){
return null;
}
//getName() 此处为获取的本类名
byte[] salt = decodeHex(sysUser.getPassword().substring(0,16));
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(sysUser,sysUser.getPassword().substring(16),
ByteSource.Util.bytes(salt),getName());
return simpleAuthenticationInfo;
}
/**
* 设定密码校验的Hash算法与迭代次数 @PostConstruct 密码加密规则 在项目加载的时候执行
*/
@PostConstruct
public void initCredentialsMatcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("SHA-1");
matcher.setHashIterations(1024);
setCredentialsMatcher(matcher);
}
/**
* Hex解码.
* @throws Exception
*/
public static byte[] decodeHex(String input){
try {
return Hex.decodeHex(input.toCharArray());
} catch (DecoderException e) {
throw new RuntimeException(e);
}
}
}
权限表
/**
* 修改公司员工信息,必须同时拥有admin角色和user:updateSysUser权限才能通过认证
* @param sysUser
* @return
*/
@RequiresRoles(value = "admin")
@RequiresPermissions("user:updateSysUser")
@RequestMapping("updateSysUser")
public ResponseState updateSysUser(SysUser sysUser){
ResponseState responseState = userService.updateSysUser(sysUser);
return responseState;
}
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import rongheng.member.entity.ResponseState;
@ControllerAdvice
public class GlobalDefaultExceptionHandler{
/**
* @RequiresPermissions("user:updateSysUser") 捕获无权限异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(UnauthorizedException.class)
@ResponseBody
public Object defaultExceptionHandler(HttpServletRequest req,Exception e){
ResponseState responseState = new ResponseState();
responseState.setState("-200");
responseState.setMsg("对不起,暂无权限!");
return responseState;
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseState {
private String state="0";
private String msg;
private String sessionid;
private String token;
private SysUser sysUser;
private Company company;
public SysUser getSysUser() {
return sysUser;
}
public void setSysUser(SysUser sysUser) {
this.sysUser = sysUser;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getSessionid() {
return sessionid;
}
public void setSessionid(String sessionid) {
this.sessionid = sessionid;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
public class StringUtils {
/**
* 获得用户远程地址
*/
public static String getRemoteAddr(HttpServletRequest request) {
String remoteAddr = request.getHeader("X-Real-IP");
if (isNotBlank(remoteAddr)) {
remoteAddr = request.getHeader("X-Forwarded-For");
} else if (isNotBlank(remoteAddr)) {
remoteAddr = request.getHeader("Proxy-Client-IP");
} else if (isNotBlank(remoteAddr)) {
remoteAddr = request.getHeader("WL-Proxy-Client-IP");
}
return remoteAddr != null ? remoteAddr : request.getRemoteAddr();
}
}
package rongheng.sales.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.StringUtils;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TokenUtil {
/**
* APP登录Token的生成和解析
*
*/
/** token秘钥,请勿泄露,请勿随便修改 backups:JKKLJOoasdlfj */
public static final String SECRET = "123";
/** token 过期时间: 10天 */
public static final int calendarField = Calendar.DATE;
public static final int calendarInterval = 10;
/**
* JWT生成Token.
*
* JWT构成: header, payload, signature
*
* @param phone
* 登录成功后用户user_id, 参数user_id不可传空
*/
public static String createToken(String phone){
try {
Date iatDate = new Date();
// expire time
/*Calendar nowTime = Calendar.getInstance();
nowTime.add(calendarField, calendarInterval);
Date expiresDate = nowTime.getTime();*/
// header Map
Map<String, Object> map = new HashMap<>(2);
map.put("alg", "HS256");
map.put("typ", "JWT");
// build token
// param backups {iss:Service, aud:APP}
String token = JWT.create().withHeader(map) // header
.withClaim("iss", "Service") // payload
.withClaim("aud", "APP").withClaim("phone", null == phone ? null : phone)
.withIssuedAt(iatDate) // sign time
//.withExpiresAt(expiresDate) // expire time
.sign(Algorithm.HMAC256(SECRET)); // signature
return token;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密Token
*
* @param token
* @return
* @throws Exception
*/
public static Map<String, Claim> verifyToken(String token) {
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
e.printStackTrace();
// token 校验失败, 抛出Token验证非法异常
}
return jwt.getClaims();
}
/**
* 根据Token获取userid
*
* @param token
* @return user_id
*/
public static String getAppUID(String token) {
Map<String, Claim> claims = verifyToken(token);
Claim user_id_claim = claims.get("phone");
if (null == user_id_claim || StringUtils.isEmpty(user_id_claim.asString())) {
// token 校验失败, 抛出Token验证非法异常
}
return String.valueOf(user_id_claim.asString());
}
}
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.Validate;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import rongheng.member.entity.Company;
import rongheng.member.entity.ResponseState;
import rongheng.member.entity.SysUser;
import rongheng.member.realm.UsernamePasswordToken;
import rongheng.member.service.pc.UserService;
import rongheng.member.utils.IdGen;
import rongheng.member.utils.StringUtils;
import rongheng.member.utils.TokenUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
@CrossOrigin
@RestController
@RequestMapping(value = "main",method = RequestMethod.POST)
public class MainAction {
@Autowired
private UserService userService;
@RequestMapping("login")
public ResponseState login(String username, String password, String rememberMe, HttpSession session,
HttpServletRequest request, HttpServletResponse response){
Subject subject = SecurityUtils.getSubject();
//设置session过期时间为永久
SecurityUtils.getSubject().getSession().setTimeout(-1);
if (password == null){
password = "";
}
String host = StringUtils.getRemoteAddr((HttpServletRequest) request);
UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray(), false, host, null,
false);
ResponseState responseState = new ResponseState();
try {
subject.login(token);
}catch (AuthenticationException e){
responseState.setMsg("用户名或者密码错误");
e.printStackTrace();
return responseState;
}
if (subject.isAuthenticated()){
session.setAttribute("user",subject.getPrincipal());
responseState.setSessionid(subject.getSession().getId().toString());//sessionid
SysUser user = userService.getUserByUsername(username);
responseState.setToken(TokenUtil.createToken(user.getPhone()));
responseState.setSysUser(user);
responseState.setState("200");
responseState.setMsg("登录成功");
return responseState;
}else {
responseState.setMsg("登录失败");
return responseState;
}
}
/**
* 用户注册
* @param sysUser
* @return
*/
@RequestMapping(value="userRegister")
public ResponseState userRegister(SysUser sysUser){
ResponseState responseState = new ResponseState();
SysUser user = userService.getUserByUsername(sysUser.getUsername());
if (user != null){
responseState.setState("405");
responseState.setMsg("账户已存在");
return responseState;
}
//验证公司是否存在
Company company = userService.verifyCompany(sysUser.getAuthorizationCode(),sysUser.getCompanyPassword());
responseState.setCompany(company);
if (company != null){
SysUser su = new SysUser();
su.setUserid(IdGen.uuid());
su.setPassword(entryptPassword(sysUser.getPassword()));
int i = userService.userRegister(su);
if (i == 1){
responseState.setSysUser(su);
responseState.setState("200");
responseState.setMsg("注册成功");
}
}else {
responseState.setState("405");
responseState.setMsg("授权码或密码错误");
}
return responseState;
}
/**
* 生成安全的密码,生成随机的16位salt并经过1024次 sha-1 hash
*/
public String entryptPassword(String plainPassword) {
String plain = unescapeHtml(plainPassword);
byte[] salt = generateSalt(8);
byte[] hashPassword = sha1(plain.getBytes(), salt, 1024);
return encodeHex(salt)+encodeHex(hashPassword);
}
/**
* Hex编码.
*/
public static String encodeHex(byte[] input) {
return new String(Hex.encodeHex(input));
}
/**
* Html 解码.
*/
public String unescapeHtml(String htmlEscaped) {
return StringEscapeUtils.unescapeHtml4(htmlEscaped);
}
/**
* 生成随机的Byte[]作为salt.
*
* @param numBytes byte数组的大小
*/
public byte[] generateSalt(int numBytes) {
SecureRandom random = new SecureRandom();
Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", numBytes);
byte[] bytes = new byte[numBytes];
random.nextBytes(bytes);
return bytes;
}
public byte[] sha1(byte[] input, byte[] salt, int iterations) {
return digest(input,"SHA-1", salt, iterations);
}
/**
* 对字符串进行散列, 支持md5与sha1算法.
*/
private byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
if (salt != null) {
digest.update(salt);
}
byte[] result = digest.digest(input);
for (int i = 1; i < iterations; i++) {
digest.reset();
result = digest.digest(result);
}
return result;
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
}