一步一步构建自己的管理系统之 ------登入注册

关于授权认证请看这篇

后台授权认证弄完了现在搞前台。 模版是用 Angular  的ngx-admin.  效果很酷炫。

重写了login component, 将原有的那个google ,facebook 等第三方登入先移除掉。查看

修改方法也很简单,自己从新注册这个component。

同理 注册页面也是一样的

国际化也已经添加 这里就不介绍了。 

下面主要的是代码逻辑。  建议可以先看一下这个文档

const NB_CORE_PROVIDERS = [
  ...DataModule.forRoot().providers,
  ...NbAuthModule.forRoot({
    providers: {
      email: {
        service: NbEmailPassAuthProvider,
        config: {
          baseEndpoint: '/api',
          delay: 500,
          login: {
            rememberMe: true,
            endpoint: '/oauth/token',
            method: 'post',
            redirect: {
              success: '/',
              failure: null,
            },
            defaultErrors: ['auth.login.loginError'],
            defaultMessages: ['auth.login.loginSuccess'],
          },
          register: {
            endpoint: '/user/register',
            method: 'post',
            redirect: {
              success: '/',
              failure: null,
            },
            defaultErrors: 'Register error',
            defaultMessages: 'Success',
          },
          token: {
            key: 'access_token',
          },
        },
      },
    },
    forms: {
      login: {
        socialLinks: socialLinks,
      },
      register: {
        socialLinks: socialLinks,
      },
    },
  }).providers,

提供一个provider. 

登入   /api/oauth/token  

注册  /api/user/register

启动的时候几个配置  proxy,

这样当你访问  /api/oauth/token 它会访问 localhost:8080/oauth/token 

angular 里面提供的http 请求时候的拦截器,在登入的时候我们在拦截器里面添加head 属性

/**
 * Created by fky on 4/4/2018.
 */
import {Injectable} from '@angular/core';
import {HttpInterceptor, HttpHandler, HttpRequest, HttpEvent} from '@angular/common/http';
import {Md5} from 'ts-md5/dist/md5'
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import {NbTokenService} from '@nebular/auth/services/token/token.service'
import 'rxjs/add/operator/switchMap';

@Injectable()
export class RequestInterceptor implements HttpInterceptor {


  constructor(private nbTokenService: NbTokenService) {

  }


  intercept(req: HttpRequest<any>,
            next: HttpHandler): Observable<HttpEvent<any>> {

    if (req.url === '/api/oauth/token') {
      const requestCopy = req.clone({
          headers: req.headers
            .append('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8') //spring auth token 验证需要这个 type
            .append('authorization', 'Basic dGVzdGp3dGNsaWVudGlkOlhZN2ttem9OemwxMDA='), // 这个是clientid 和client_secret basic 
          body: 'username=' + req.body.email + '&password=' + Md5.hashStr(req.body.password) + '&grant_type=password',  
        },
      );
      return next.handle(requestCopy);
    } else if (req.url === '/api/user/register') {
      const requestCopy = req.clone({
          body: {
            email: req.body.email,
            username: req.body.username,
            password: Md5.hashStr(req.body.password),
            confirmPassword: Md5.hashStr(req.body.confirmPassword),
            terms: req.body.terms,
          },
        },
      );
      return next.handle(requestCopy);
    } else {
      return this.nbTokenService.get().switchMap(tokenObj => {
        const token = tokenObj.getValue();
        const requestCopy = req.clone({
          headers: req.headers
            .append('Authorization', 'Bearer ' + token),
        });
        return next.handle(requestCopy);
      });
    }
  }
}

登入时候我把密码MD5了一下。 

登入的后台验证过程都是spring完成的, 我们只是之前配置了一下。 逻辑可以看一下源码

类:org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.class

@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
	public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
	Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {

		if (!(principal instanceof Authentication)) {
			throw new InsufficientAuthenticationException(
					"There is no client authentication. Try adding an appropriate authentication filter.");
		}

		String clientId = getClientId(principal);
		ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);

		TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);

		if (clientId != null && !clientId.equals("")) {
			// Only validate the client details if a client authenticated during this
			// request.
			if (!clientId.equals(tokenRequest.getClientId())) {
				// double check to make sure that the client ID in the token request is the same as that in the
				// authenticated client
				throw new InvalidClientException("Given client ID does not match authenticated client");
			}
		}
		if (authenticatedClient != null) {
			oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
		}
		if (!StringUtils.hasText(tokenRequest.getGrantType())) {
			throw new InvalidRequestException("Missing grant type");
		}
		if (tokenRequest.getGrantType().equals("implicit")) {
			throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
		}

		if (isAuthCodeRequest(parameters)) {
			// The scope was requested or determined during the authorization step
			if (!tokenRequest.getScope().isEmpty()) {
				logger.debug("Clearing scope of incoming token request");
				tokenRequest.setScope(Collections.<String> emptySet());
			}
		}

		if (isRefreshTokenRequest(parameters)) {
			// A refresh token has its own default scopes, so we should ignore any added by the factory here.
			tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
		}

		OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
		if (token == null) {
			throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
		}

		return getResponse(token);

	}

登入成功 返回一串token 值 , 后续验证用户时候只要带这串token 就可以了。 

注册 后台controller

@RestController
@RequestMapping("/user")
public class UserController {

	@Autowired
	private UserServcie userService;

	@RequestMapping(value = "/register", method = RequestMethod.POST)
	public ResponseEntity<OAuth2AccessToken> register(@RequestBody User user) throws RestException {
		OAuth2AccessToken token = userService.registerUser(user);
		HttpHeaders headers = new HttpHeaders();
		headers.set("Cache-Control", "no-store");
		headers.set("Pragma", "no-cache");
		return new ResponseEntity<OAuth2AccessToken>(token, headers, HttpStatus.OK);
	}

}
@Override
	public OAuth2AccessToken registerUser(User user) throws RestException {

		User u = userDAO.findByEmail(user.getEmail());
		if (u != null) {
			throw new RestException("User email exist");
		}

		User copy = new User();
		BeanUtils.copyProperties(user, copy);
		
		// 将得到的 md5 密码再加密一边存数据库
		// encode password
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		copy.setPassword(encoder.encode(user.getPassword()));
		userDAO.registerUser(copy);
		
		return createToken(user);
	}

	private OAuth2AccessToken createToken(User user) {
		Map<String,String> param = new HashMap<>();
		
		param.put("username", user.getEmail());
		param.put("password", user.getPassword());
		param.put("grant_type", grantType);
		
		Set<String> scopes = new HashSet<>();
		scopes.add(scopeRead);
		scopes.add(scopeWrite);
		
		TokenRequest tokenRequest = new TokenRequest(param, clientId, scopes, grantType);
		ClientDetails authenticatedClient =  clientDetailsService.loadClientByClientId(clientId);
		
		//user password authentication token
		Authentication userAuth = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
		param.remove("password");
		((AbstractAuthenticationToken) userAuth).setDetails(param);
		
		userAuth = authenticationManager.authenticate(userAuth);
		return tokenServices.createAccessToken(new OAuth2Authentication(tokenRequest.createOAuth2Request(authenticatedClient), userAuth));
	}

写注册时候 成功的时候要返回token 给我一阵好整。 分析了login的整个流程,用新注册的账号重新模拟再登入一遍。 返回token 前台直接跳到home page.

仓库:https://gitee.com/codefans/fmanager 

          https://gitee.com/codefans/admin-cli

欢迎小伙伴加入一起玩耍

猜你喜欢

转载自my.oschina.net/u/241688/blog/1796475